mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Compare commits
337 Commits
v2.0.0-rc1
...
v2.0.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b52719fd73 | ||
|
|
7953976d25 | ||
|
|
39d6b94835 | ||
|
|
4fdce0695d | ||
|
|
ae8247fe6a | ||
|
|
d664565174 | ||
|
|
b24a46ad8f | ||
|
|
6bffe34faa | ||
|
|
abe3fb4acb | ||
|
|
39905bd8fd | ||
|
|
078dbfb0a9 | ||
|
|
dfeb5cfdd2 | ||
|
|
c1777cfb89 | ||
|
|
974072bdae | ||
|
|
b95e18956f | ||
|
|
3c1c5ef281 | ||
|
|
7194b14cd2 | ||
|
|
4e6f8d561c | ||
|
|
ac26921569 | ||
|
|
a60543728b | ||
|
|
f35ec9771e | ||
|
|
de4fe99e34 | ||
|
|
8ea6b3eebd | ||
|
|
a01836fe8d | ||
|
|
268dc97857 | ||
|
|
fc203c9654 | ||
|
|
8eedd5b277 | ||
|
|
561d9ac2bc | ||
|
|
1112da76f1 | ||
|
|
081aa18f39 | ||
|
|
c05c8bbba1 | ||
|
|
eabd23f31e | ||
|
|
cc27088df9 | ||
|
|
97ab7e9c65 | ||
|
|
bbf92828f6 | ||
|
|
2f83bf9f83 | ||
|
|
b2a1728201 | ||
|
|
18cbbbe9aa | ||
|
|
d90f8a3697 | ||
|
|
fe3ef6fc2e | ||
|
|
1b9148f12f | ||
|
|
deb8e49483 | ||
|
|
d75af2a156 | ||
|
|
9895edefff | ||
|
|
b60e856087 | ||
|
|
6244b4d00f | ||
|
|
ee167b1a43 | ||
|
|
e8b9bfe44c | ||
|
|
50f5593ffc | ||
|
|
3f0f7acbc0 | ||
|
|
7f6f8ec386 | ||
|
|
24d1798779 | ||
|
|
3e9d603f0b | ||
|
|
71a8fd3106 | ||
|
|
49279a3c19 | ||
|
|
43a1291f7c | ||
|
|
6dc5340f60 | ||
|
|
2a6e33bc73 | ||
|
|
0f6b2cfd3d | ||
|
|
30d109c0e9 | ||
|
|
e8e1f844d9 | ||
|
|
05a89e5566 | ||
|
|
c122889c95 | ||
|
|
9de5dc932b | ||
|
|
289c9ecf5d | ||
|
|
2c1a6e3f94 | ||
|
|
ad092a898d | ||
|
|
56f2548b6e | ||
|
|
25467243a6 | ||
|
|
e07d40fc26 | ||
|
|
09877e4e63 | ||
|
|
d3460b6cf5 | ||
|
|
ba384d15d2 | ||
|
|
2f38ade0e0 | ||
|
|
4d110d4c82 | ||
|
|
1bf5ff3e6e | ||
|
|
cd2a1a169f | ||
|
|
59b5f360af | ||
|
|
e8b6890318 | ||
|
|
d7b9ed05f0 | ||
|
|
dc852a100f | ||
|
|
838d51d296 | ||
|
|
e2845bc032 | ||
|
|
8c021fd784 | ||
|
|
406ec14585 | ||
|
|
c27b42e425 | ||
|
|
2d94d7ab0c | ||
|
|
5fcf430c81 | ||
|
|
cea4b3e363 | ||
|
|
e00d8fb544 | ||
|
|
e654fabe04 | ||
|
|
18592a08be | ||
|
|
1763260578 | ||
|
|
955f10e621 | ||
|
|
2565fedeb7 | ||
|
|
6b8e553ecc | ||
|
|
14f81cb275 | ||
|
|
ddb844226d | ||
|
|
f87ee5112a | ||
|
|
2a1a773777 | ||
|
|
7fede3ee45 | ||
|
|
abcd3511bf | ||
|
|
a387557970 | ||
|
|
daba04d54b | ||
|
|
b00a87d8fa | ||
|
|
aee55b0595 | ||
|
|
e58883c183 | ||
|
|
321e840c1c | ||
|
|
19ac1dd393 | ||
|
|
13796ee4c7 | ||
|
|
10bb78458d | ||
|
|
6997506bb9 | ||
|
|
480c7178a8 | ||
|
|
0279d8f466 | ||
|
|
1a6183d0c4 | ||
|
|
487acbb573 | ||
|
|
f97eba6539 | ||
|
|
cac84abdd9 | ||
|
|
ef045f9f65 | ||
|
|
6002099288 | ||
|
|
181f621a90 | ||
|
|
5a71c6f2eb | ||
|
|
487965dc8a | ||
|
|
874c573bd4 | ||
|
|
f63e1cfbfc | ||
|
|
f049f719f8 | ||
|
|
30754473fc | ||
|
|
7c70e6ce74 | ||
|
|
a702b7ccc5 | ||
|
|
f6be62ac5f | ||
|
|
dddd30bef8 | ||
|
|
a054206d25 | ||
|
|
5b6f06b2ac | ||
|
|
6f83822b6e | ||
|
|
9b635a3e90 | ||
|
|
172af5465d | ||
|
|
22f10dd8d2 | ||
|
|
790fdc0aa6 | ||
|
|
45356f5e12 | ||
|
|
08ee50403d | ||
|
|
aa1551c6e8 | ||
|
|
879403a172 | ||
|
|
6ddf765d8d | ||
|
|
38d83c27b4 | ||
|
|
103fa8fa2c | ||
|
|
53dcee6176 | ||
|
|
0c6129c54e | ||
|
|
1f01754ea6 | ||
|
|
f8a7ab1752 | ||
|
|
09842ce46f | ||
|
|
0b849985b2 | ||
|
|
34b8a48252 | ||
|
|
6f6e1efbc8 | ||
|
|
9a72ec366d | ||
|
|
d97302f351 | ||
|
|
4eb75f3c80 | ||
|
|
e5f72a0d4f | ||
|
|
b11b11f9b0 | ||
|
|
70077db07d | ||
|
|
eed682c529 | ||
|
|
fbf2d64f34 | ||
|
|
48bf08922c | ||
|
|
3616ee50c0 | ||
|
|
255c8e8ff4 | ||
|
|
0891e84bf8 | ||
|
|
a63db4ab24 | ||
|
|
169d45fbdb | ||
|
|
965e0237a3 | ||
|
|
4caef0dec7 | ||
|
|
622763b240 | ||
|
|
35d29b22c0 | ||
|
|
fee1d659cf | ||
|
|
869767a5cf | ||
|
|
23b01621ff | ||
|
|
f21ebaf839 | ||
|
|
f6f00b98a7 | ||
|
|
187170ec51 | ||
|
|
f7ad64a3d3 | ||
|
|
103d75f773 | ||
|
|
ed2968e3e8 | ||
|
|
fef5121cee | ||
|
|
c84983f91e | ||
|
|
86f4f4440a | ||
|
|
af0887fb48 | ||
|
|
610c7858d6 | ||
|
|
8d1fb88a20 | ||
|
|
1e2ad19d68 | ||
|
|
7bee66fe36 | ||
|
|
303fe886b7 | ||
|
|
761a472b45 | ||
|
|
3cf2da877f | ||
|
|
5b7b1596a2 | ||
|
|
dc58985ac6 | ||
|
|
5e0db46f17 | ||
|
|
4e19bc01d5 | ||
|
|
2d2acda404 | ||
|
|
fa8d5d1769 | ||
|
|
fe058e2c27 | ||
|
|
a22a24bc98 | ||
|
|
b7c2465887 | ||
|
|
f34158250a | ||
|
|
87dcc9fe07 | ||
|
|
c56e0eb556 | ||
|
|
ba959970c6 | ||
|
|
c75e31d3da | ||
|
|
bcc2330a18 | ||
|
|
f0f5913efe | ||
|
|
17aefd333a | ||
|
|
b86a652b90 | ||
|
|
5968323642 | ||
|
|
26727882d0 | ||
|
|
106e441a61 | ||
|
|
6d22ba9f87 | ||
|
|
8cd9db272f | ||
|
|
b8691649c5 | ||
|
|
e9a2938c6b | ||
|
|
44fa0bfbc6 | ||
|
|
36c213ed3a | ||
|
|
5f26f8a03d | ||
|
|
471f781022 | ||
|
|
f6cb8e4118 | ||
|
|
515eff269c | ||
|
|
bd370ab789 | ||
|
|
3e10116437 | ||
|
|
05f665ecda | ||
|
|
cd65f6a84d | ||
|
|
6d2979459e | ||
|
|
dee38e9c0b | ||
|
|
b4fc36ea62 | ||
|
|
fb6b4739e4 | ||
|
|
32700cc51b | ||
|
|
1ac353d24e | ||
|
|
d7686201dc | ||
|
|
248733de44 | ||
|
|
e410ba9623 | ||
|
|
8295bde95a | ||
|
|
f3a9e95dd8 | ||
|
|
7378e3be01 | ||
|
|
1968efe9f0 | ||
|
|
2b6808f165 | ||
|
|
92f14d28d1 | ||
|
|
954214e48c | ||
|
|
828e6f2077 | ||
|
|
982b7373ea | ||
|
|
39b5359efd | ||
|
|
627a538bf2 | ||
|
|
e07e3ecc22 | ||
|
|
b426db6086 | ||
|
|
d4b43d8578 | ||
|
|
b9b1680f08 | ||
|
|
3e37975a00 | ||
|
|
b0e252684d | ||
|
|
919e1c3f08 | ||
|
|
16dc58312c | ||
|
|
169bd9db5e | ||
|
|
4e5e8fd8fe | ||
|
|
8728ba08e2 | ||
|
|
3ba07ed27f | ||
|
|
9b4b659804 | ||
|
|
c00a31077c | ||
|
|
e8fc17f816 | ||
|
|
4a2da4b51e | ||
|
|
180d96234e | ||
|
|
1a04ffbae4 | ||
|
|
1fe014dbae | ||
|
|
579c31aa23 | ||
|
|
74c914475f | ||
|
|
1ca439f4e0 | ||
|
|
08e7c143b3 | ||
|
|
d399dfa792 | ||
|
|
f6e613a76f | ||
|
|
c6a8b6471a | ||
|
|
83589b7cec | ||
|
|
aeea93fa95 | ||
|
|
be417d6605 | ||
|
|
2f890dea18 | ||
|
|
de76628539 | ||
|
|
598dd672bc | ||
|
|
d12fb3d6e1 | ||
|
|
9504d866b6 | ||
|
|
865b1dc66e | ||
|
|
5143b210cf | ||
|
|
f34ce81f25 | ||
|
|
b072c6c4c9 | ||
|
|
7951ed3bce | ||
|
|
02431c57db | ||
|
|
3f186c009c | ||
|
|
6f4c15b2b2 | ||
|
|
b31e029000 | ||
|
|
5f5ffcd48a | ||
|
|
cc76f3746f | ||
|
|
982da4d20c | ||
|
|
113374fd04 | ||
|
|
e4520693dd | ||
|
|
ccffc88ceb | ||
|
|
7c9312607c | ||
|
|
286c2960c8 | ||
|
|
a12e374a04 | ||
|
|
d799c8bd1e | ||
|
|
251eec8401 | ||
|
|
bca8a32674 | ||
|
|
c740324636 | ||
|
|
f049afcb5b | ||
|
|
c188654ebd | ||
|
|
a6aba8cab2 | ||
|
|
583fbfdb2a | ||
|
|
7c34ac6f6d | ||
|
|
b72354ca22 | ||
|
|
82d81b9e86 | ||
|
|
ed19ddf620 | ||
|
|
ebbd33db7a | ||
|
|
7ba4ca1854 | ||
|
|
fa1f8c0d87 | ||
|
|
e0cacef52e | ||
|
|
767ed40b75 | ||
|
|
3c2f92a7af | ||
|
|
2568f828c8 | ||
|
|
5427f55358 | ||
|
|
92b41e4935 | ||
|
|
6edae6ddef | ||
|
|
f787eafd8a | ||
|
|
9588a961d6 | ||
|
|
88758703fa | ||
|
|
3c839f44d8 | ||
|
|
304bdd7d0d | ||
|
|
382d27b4dc | ||
|
|
b80278c04f | ||
|
|
7d4fcfa191 | ||
|
|
ad3fe00dea | ||
|
|
f507d16baa | ||
|
|
dcce2edc4f | ||
|
|
e7e1e7a0a3 | ||
|
|
68f4485cdd | ||
|
|
d93ac3c496 | ||
|
|
a97de38b6b | ||
|
|
444eac3597 | ||
|
|
1f01c76fa5 |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -6,10 +6,12 @@ Makefile.in.in
|
||||
*.lo
|
||||
*.la
|
||||
*.o
|
||||
**/*.dirstamp
|
||||
.deps/
|
||||
.libs/
|
||||
src/cryptsetup
|
||||
src/veritysetup
|
||||
ABOUT-NLS
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
compile
|
||||
@@ -21,8 +23,11 @@ config.rpath
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
cryptsetup
|
||||
cryptsetup-reencrypt
|
||||
depcomp
|
||||
install-sh
|
||||
integritysetup
|
||||
lib/libcryptsetup.pc
|
||||
libtool
|
||||
ltmain.sh
|
||||
@@ -36,5 +41,7 @@ po/*.header
|
||||
po/*.sed
|
||||
po/*.sin
|
||||
po/stamp-po
|
||||
scripts/cryptsetup.conf
|
||||
stamp-h1
|
||||
|
||||
veritysetup
|
||||
tests/valglog.*
|
||||
|
||||
@@ -38,6 +38,7 @@ function check_nonroot
|
||||
configure_travis \
|
||||
--enable-python \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
@@ -50,9 +51,7 @@ function check_nonroot
|
||||
sudo dmsetup version
|
||||
sudo dmsetup targets
|
||||
|
||||
make check || return
|
||||
|
||||
#sudo $MAKE install || return
|
||||
make check
|
||||
}
|
||||
|
||||
function check_root
|
||||
@@ -64,6 +63,7 @@ function check_root
|
||||
configure_travis \
|
||||
--enable-python \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
@@ -77,9 +77,7 @@ function check_root
|
||||
sudo dmsetup targets
|
||||
|
||||
# FIXME: we should use -E option here
|
||||
sudo make check || return
|
||||
|
||||
#sudo $MAKE install || return
|
||||
sudo make check
|
||||
}
|
||||
|
||||
function check_nonroot_compile_only
|
||||
@@ -91,6 +89,7 @@ function check_nonroot_compile_only
|
||||
configure_travis \
|
||||
--enable-python \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
@@ -120,6 +119,7 @@ function travis_install_script
|
||||
expect \
|
||||
keyutils \
|
||||
libjson-c-dev \
|
||||
libblkid-dev \
|
||||
|| return
|
||||
}
|
||||
|
||||
@@ -141,14 +141,14 @@ function travis_script
|
||||
|
||||
case "$MAKE_CHECK" in
|
||||
gcrypt)
|
||||
check_nonroot "--with-crypto_backend=gcrypt"
|
||||
check_nonroot "--with-crypto_backend=gcrypt" && \
|
||||
check_root "--with-crypto_backend=gcrypt"
|
||||
;;
|
||||
gcrypt_compile)
|
||||
check_nonroot_compile_only "--with-crypto_backend=gcrypt"
|
||||
;;
|
||||
openssl)
|
||||
check_nonroot "--with-crypto_backend=openssl"
|
||||
check_nonroot "--with-crypto_backend=openssl" && \
|
||||
check_root "--with-crypto_backend=openssl"
|
||||
;;
|
||||
openssl_compile)
|
||||
|
||||
8
FAQ
8
FAQ
@@ -128,7 +128,7 @@ A. Contributors
|
||||
recommended to not install Ubuntu on a system with existing LUKS
|
||||
containers without complete backups.
|
||||
|
||||
Update 11/2014: There seem to be other problems withe existing LUKS
|
||||
Update 11/2014: There seem to be other problems with existing LUKS
|
||||
containers and Ubuntu as well, be extra careful when using LUKS
|
||||
on Ubuntu in any way, but exactly as the Ubuntu installer does.
|
||||
|
||||
@@ -209,7 +209,7 @@ A. Contributors
|
||||
to send it from your list address.
|
||||
|
||||
The mailing list archive is here:
|
||||
http://dir.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt
|
||||
https://marc.info/?l=dm-crypt
|
||||
|
||||
|
||||
* 1.8 Unsubscribe from the mailing-list
|
||||
@@ -2475,7 +2475,7 @@ offset length name data type description
|
||||
|
||||
More details:
|
||||
|
||||
Cipher, mode and pasword hash (or no hash):
|
||||
Cipher, mode and password hash (or no hash):
|
||||
|
||||
-e cipher [-N] => -c cipher-cbc-plain -H plain [-s 256]
|
||||
-e cipher => -c cipher-cbc-plain -H ripemd160 [-s 256]
|
||||
@@ -2616,7 +2616,7 @@ My take is this was much more driven by some big egos that wanted
|
||||
to make a splash for self-aggrandizement, than by any actual
|
||||
security concerns. Ignore it.
|
||||
|
||||
* 9.3 How do I do my own inird with cryptsetup?
|
||||
* 9.3 How do I do my own initrd with cryptsetup?
|
||||
|
||||
It depends on the distribution. Below, I give a very simple example
|
||||
and step-by-step instructions for Debian. With a bit of work, it
|
||||
|
||||
2
INSTALL
2
INSTALL
@@ -44,7 +44,7 @@ The simplest way to compile this package is:
|
||||
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||
`configure' itself.
|
||||
|
||||
Running `configure' takes awhile. While running, it prints some
|
||||
Running `configure' takes a while. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
@@ -29,7 +29,9 @@ include python/Makemodule.am
|
||||
|
||||
include scripts/Makemodule.am
|
||||
|
||||
if CRYPTO_INTERNAL_ARGON2
|
||||
include lib/crypto_backend/argon2/Makemodule.am
|
||||
endif
|
||||
include lib/crypto_backend/Makemodule.am
|
||||
include lib/Makemodule.am
|
||||
|
||||
@@ -39,11 +41,12 @@ ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--enable-python \
|
||||
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d
|
||||
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d \
|
||||
--enable-internal-argon2 --enable-internal-sse-argon2
|
||||
|
||||
distclean-local:
|
||||
-find . -name \*~ -o -name \*.orig -o -name \*.rej | xargs rm -f
|
||||
rm -rf autom4te.cache
|
||||
|
||||
clean-local:
|
||||
-rm -rf docs/doxygen_api_docs
|
||||
-rm -rf docs/doxygen_api_docs libargon2.la
|
||||
|
||||
32
README.md
32
README.md
@@ -26,7 +26,7 @@ Last version of the LUKS format specification is
|
||||
|
||||
Why LUKS?
|
||||
---------
|
||||
* compatiblity via standardization,
|
||||
* compatibility via standardization,
|
||||
* secure against low entropy attacks,
|
||||
* support for multiple keys,
|
||||
* effective passphrase revocation,
|
||||
@@ -42,19 +42,25 @@ Download
|
||||
--------
|
||||
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
|
||||
|
||||
**The latest cryptsetup TESTING version is 2.0.0-rc1**
|
||||
* [cryptsetup-2.0.0-rc1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0-rc1.tar.xz)
|
||||
* Signature [cryptsetup-2.0.0-rc1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0-rc1.tar.sign)
|
||||
**The latest cryptsetup version is 2.0.3**
|
||||
* [cryptsetup-2.0.3.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.3.tar.xz)
|
||||
* Signature [cryptsetup-2.0.3.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.3.tar.sign)
|
||||
_(You need to decompress file first to check signature.)_
|
||||
* [Cryptsetup 2.0.0-rc1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.0-rc1-ReleaseNotes).
|
||||
|
||||
**The latest cryptsetup version is 1.7.5**
|
||||
* [cryptsetup-1.7.5.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz)
|
||||
* Signature [cryptsetup-1.7.5.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign)
|
||||
_(You need to decompress file first to check signature.)_
|
||||
* [Cryptsetup 1.7.5 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
|
||||
* [Cryptsetup 2.0.3 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.3-ReleaseNotes).
|
||||
|
||||
Previous versions
|
||||
* [Version 2.0.2](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.2.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.2.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.2-ReleaseNotes).
|
||||
* [Version 2.0.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.1-ReleaseNotes).
|
||||
* [Version 2.0.0](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.0-ReleaseNotes).
|
||||
* [Version 1.7.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
|
||||
* [Version 1.7.4](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.4.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.4.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.4-ReleaseNotes).
|
||||
@@ -78,7 +84,7 @@ mirror on [kernel.org](https://git.kernel.org/cgit/utils/cryptsetup/cryptsetup.g
|
||||
|
||||
For libcryptsetup documentation see [libcryptsetup API](https://gitlab.com/cryptsetup/cryptsetup/wikis/API/index.html) page.
|
||||
|
||||
The libcryptsetup API/ABI changes are tracked in [compatibility report](https://gitlab.com/cryptsetup/cryptsetup/wikis/ABI-tracker/timeline/libcryptsetup/index.html).
|
||||
The libcryptsetup API/ABI changes are tracked in [compatibility report](https://abi-laboratory.pro/tracker/timeline/cryptsetup/).
|
||||
|
||||
NLS PO files are maintained by [TranslationProject](http://translationproject.org/domain/cryptsetup.html).
|
||||
|
||||
@@ -90,4 +96,4 @@ For cryptsetup and LUKS related questions, please use the dm-crypt mailing list,
|
||||
If you want to subscribe just send an empty mail to [dm-crypt-subscribe@saout.de](mailto:dm-crypt-subscribe@saout.de).
|
||||
|
||||
You can also browse [list archive](http://www.saout.de/pipermail/dm-crypt/) or read it through
|
||||
[web interface](http://news.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt).
|
||||
[web interface](https://marc.info/?l=dm-crypt).
|
||||
|
||||
6
TODO
6
TODO
@@ -1,5 +1 @@
|
||||
- Support K/M suffixes for align payload (new switch?).
|
||||
- Do we need crypt_data_path() - path to data device (if differs)?
|
||||
- Resync ETA time is not accurate, calculate it better (last minute window?).
|
||||
- Fix all crazy automake warnings (or switch to Cmake).
|
||||
- Nettle3 backend is not compatible
|
||||
Please see issues tracked at https://gitlab.com/cryptsetup/cryptsetup/issues.
|
||||
|
||||
100
configure.ac
100
configure.ac
@@ -1,9 +1,9 @@
|
||||
AC_PREREQ([2.67])
|
||||
AC_INIT([cryptsetup],[2.0.0-rc1])
|
||||
AC_INIT([cryptsetup],[2.0.4])
|
||||
|
||||
dnl library version from <major>.<minor>.<release>[-<suffix>]
|
||||
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
|
||||
LIBCRYPTSETUP_VERSION_INFO=12:0:0
|
||||
LIBCRYPTSETUP_VERSION_INFO=15:0:3
|
||||
|
||||
AM_SILENT_RULES([yes])
|
||||
AC_CONFIG_SRCDIR(src/cryptsetup.c)
|
||||
@@ -403,14 +403,64 @@ AC_ARG_ENABLE([libargon2], AS_HELP_STRING([--enable-libargon2],
|
||||
if test x$enable_libargon2 = xyes ; then
|
||||
AC_CHECK_HEADERS(argon2.h,,
|
||||
[AC_MSG_ERROR([You need libargon2 development library installed.])])
|
||||
AC_CHECK_DECL(Argon2_id,,[AC_MSG_ERROR([You need more recent Argon2 library with support for Argon2id.])], [#include <argon2.h>])
|
||||
PKG_CHECK_MODULES([LIBARGON2], [libargon2],,[LIBARGON2_LIBS="-largon2"])
|
||||
enable_internal_argon2=no
|
||||
else
|
||||
AC_MSG_WARN([Argon2 bundled (slow) reference implementation will be used, please consider to use system library with --enable-libargon2.])
|
||||
|
||||
AC_ARG_ENABLE(internal-sse-argon2, AS_HELP_STRING([--enable-internal-sse-argon2],
|
||||
[enable internal SSE implementation of Argon2 PBKDF]),[], [enable_internal_sse_argon2=no])
|
||||
|
||||
if test x$enable_internal_sse_argon2 = xyes ; then
|
||||
AC_MSG_CHECKING(if Argon2 SSE optimization can be used)
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <emmintrin.h>
|
||||
__m128i testfunc(__m128i *a, __m128i *b) {
|
||||
return _mm_xor_si128(_mm_loadu_si128(a), _mm_loadu_si128(b));
|
||||
}
|
||||
]])],,[enable_internal_sse_argon2=no])
|
||||
AC_MSG_RESULT($enable_internal_sse_argon2)
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x$enable_internal_argon2 = xyes ; then
|
||||
AC_DEFINE(USE_INTERNAL_ARGON2, 1, [Use internal Argon2])
|
||||
fi
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_ARGON2, test x$enable_internal_argon2 = xyes)
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_SSE_ARGON2, test x$enable_internal_sse_argon2 = xyes)
|
||||
|
||||
dnl Link with blkid to check for other device types
|
||||
AC_ARG_ENABLE(blkid, AS_HELP_STRING([--disable-blkid],
|
||||
[disable use of blkid for device signature detection and wiping.]), [], [enable_blkid=yes])
|
||||
|
||||
if test x$enable_blkid = xyes ; then
|
||||
PKG_CHECK_MODULES([BLKID], [blkid],[AC_DEFINE([HAVE_BLKID], 1, [Define to 1 to use blkid for detection of disk signatures.])],[LIBBLKID_LIBS="-lblkid"])
|
||||
|
||||
AC_CHECK_HEADERS(blkid/blkid.h,,[AC_MSG_ERROR([You need blkid development library installed.])])
|
||||
AC_CHECK_DECL([blkid_do_wipe],
|
||||
[ AC_DEFINE([HAVE_BLKID_WIPE], 1, [Define to 1 to use blkid_do_wipe.])
|
||||
enable_blkid_wipe=yes
|
||||
],,
|
||||
[#include <blkid/blkid.h>])
|
||||
AC_CHECK_DECL([blkid_probe_step_back],
|
||||
[ AC_DEFINE([HAVE_BLKID_STEP_BACK], 1, [Define to 1 to use blkid_probe_step_back.])
|
||||
enable_blkid_step_back=yes
|
||||
],,
|
||||
[#include <blkid/blkid.h>])
|
||||
AC_CHECK_DECLS([ blkid_reset_probe,
|
||||
blkid_probe_set_device,
|
||||
blkid_probe_filter_superblocks_type,
|
||||
blkid_do_safeprobe,
|
||||
blkid_do_probe,
|
||||
blkid_probe_lookup_value
|
||||
],,
|
||||
[AC_MSG_ERROR([Can not compile with blkid support, disable it by --disable-blkid.])],
|
||||
[#include <blkid/blkid.h>])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_BLKID, test x$enable_blkid = xyes)
|
||||
AM_CONDITIONAL(HAVE_BLKID_WIPE, test x$enable_blkid_wipe = xyes)
|
||||
AM_CONDITIONAL(HAVE_BLKID_STEP_BACK, test x$enable_blkid_step_back = xyes)
|
||||
|
||||
dnl Magic for cryptsetup.static build.
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
@@ -462,14 +512,19 @@ AC_SUBST([CRYPTO_STATIC_LIBS])
|
||||
|
||||
AC_SUBST([JSON_C_LIBS])
|
||||
AC_SUBST([LIBARGON2_LIBS])
|
||||
AC_SUBST([BLKID_LIBS])
|
||||
|
||||
AC_SUBST([LIBCRYPTSETUP_VERSION])
|
||||
AC_SUBST([LIBCRYPTSETUP_VERSION_INFO])
|
||||
|
||||
dnl ==========================================================================
|
||||
AC_ARG_ENABLE([dev-random], AS_HELP_STRING([--enable-dev-random],
|
||||
[use blocking /dev/random by default for key generator (otherwise use /dev/urandom)]),
|
||||
[default_rng=/dev/random], [default_rng=/dev/urandom])
|
||||
AC_ARG_ENABLE([dev-random],
|
||||
AS_HELP_STRING([--enable-dev-random], [use /dev/random by default for key generation (otherwise use /dev/urandom)]))
|
||||
if test "x$enable_dev_random" = "xyes"; then
|
||||
default_rng=/dev/random
|
||||
else
|
||||
default_rng=/dev/urandom
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_RNG, ["$default_rng"], [default RNG type for key generator])
|
||||
|
||||
dnl ==========================================================================
|
||||
@@ -489,6 +544,13 @@ AC_DEFUN([CS_NUM_WITH], [AC_ARG_WITH([$1],
|
||||
[CS_DEFINE([$1], [$3], [$2])]
|
||||
)])
|
||||
|
||||
AC_DEFUN([CS_ABSPATH], [
|
||||
case "$1" in
|
||||
/*) ;;
|
||||
*) AC_MSG_ERROR([$2 argument must be an absolute path.]);;
|
||||
esac
|
||||
])
|
||||
|
||||
dnl ==========================================================================
|
||||
dnl Python bindings
|
||||
AC_ARG_ENABLE([python], AS_HELP_STRING([--enable-python],[enable Python bindings]),
|
||||
@@ -532,8 +594,8 @@ CS_NUM_WITH([luks1-keybits],[key length in bits for LUKS1], [256])
|
||||
|
||||
CS_STR_WITH([luks2-pbkdf], [Default PBKDF algorithm (pbkdf2 or argon2i/argon2id) for LUKS2], [argon2i])
|
||||
CS_NUM_WITH([luks1-iter-time], [PBKDF2 iteration time for LUKS1 (in ms)], [2000])
|
||||
CS_NUM_WITH([luks2-iter-time], [Argon2 PBKDF iteration time for LUKS2 (in ms)], [800])
|
||||
CS_NUM_WITH([luks2-memory-kb], [Argon2 PBKDF memory cost for LUKS2 (in kB)], [131072])
|
||||
CS_NUM_WITH([luks2-iter-time], [Argon2 PBKDF iteration time for LUKS2 (in ms)], [2000])
|
||||
CS_NUM_WITH([luks2-memory-kb], [Argon2 PBKDF memory cost for LUKS2 (in kB)], [1048576])
|
||||
CS_NUM_WITH([luks2-parallel-threads],[Argon2 PBKDF max parallel cost for LUKS2 (if CPUs available)], [4])
|
||||
|
||||
CS_STR_WITH([loopaes-cipher], [cipher for loop-AES mode], [aes])
|
||||
@@ -550,17 +612,16 @@ CS_NUM_WITH([verity-fec-roots], [parity bytes for verity FEC], [2])
|
||||
|
||||
CS_STR_WITH([tmpfilesdir], [override default path to directory with systemd temporary files], [])
|
||||
test -z "$with_tmpfilesdir" && with_tmpfilesdir=$systemd_tmpfilesdir
|
||||
test "x$with_tmpfilesdir" == "xno" || {
|
||||
test "${with_tmpfilesdir:0:1}" = "/" || AC_MSG_ERROR([--with-tmpfilesdir argument must be an absolute path.])
|
||||
test "x$with_tmpfilesdir" = "xno" || {
|
||||
CS_ABSPATH([${with_tmpfilesdir}],[with-tmpfilesdir])
|
||||
DEFAULT_TMPFILESDIR=$with_tmpfilesdir
|
||||
AC_SUBST(DEFAULT_TMPFILESDIR)
|
||||
}
|
||||
AM_CONDITIONAL(CRYPTSETUP_TMPFILE, test -n "$DEFAULT_TMPFILESDIR")
|
||||
|
||||
|
||||
CS_STR_WITH([luks2-lock-path], [path to directory for LUKSv2 locks], [/run/lock/cryptsetup])
|
||||
test -z "$with_luks2_lock_path" && with_luks2_lock_path=/run/lock/cryptsetup
|
||||
test "${with_luks2_lock_path:0:1}" = "/" || AC_MSG_ERROR([--with-luks2-lock-path argument must be an absolute path.])
|
||||
CS_STR_WITH([luks2-lock-path], [path to directory for LUKSv2 locks], [/run/cryptsetup])
|
||||
test -z "$with_luks2_lock_path" && with_luks2_lock_path=/run/cryptsetup
|
||||
CS_ABSPATH([${with_luks2_lock_path}],[with-luks2-lock-path])
|
||||
DEFAULT_LUKS2_LOCK_PATH=$with_luks2_lock_path
|
||||
AC_SUBST(DEFAULT_LUKS2_LOCK_PATH)
|
||||
|
||||
@@ -569,6 +630,19 @@ test -z "$with_luks2_lock_dir_perms" && with_luks2_lock_dir_perms=0700
|
||||
DEFAULT_LUKS2_LOCK_DIR_PERMS=$with_luks2_lock_dir_perms
|
||||
AC_SUBST(DEFAULT_LUKS2_LOCK_DIR_PERMS)
|
||||
|
||||
dnl Override default LUKS format version (for cryptsetup or cryptsetup-reencrypt format actions only).
|
||||
AC_ARG_WITH([default_luks_format],
|
||||
AS_HELP_STRING([--with-default-luks-format=FORMAT], [default LUKS format version (LUKS1/LUKS2) [LUKS1]]),
|
||||
[], with_default_luks_format=LUKS1
|
||||
)
|
||||
|
||||
case $with_default_luks_format in
|
||||
LUKS1) default_luks=CRYPT_LUKS1 ;;
|
||||
LUKS2) default_luks=CRYPT_LUKS2 ;;
|
||||
*) AC_MSG_ERROR([Unknown default LUKS format. Use LUKS1 or LUKS2 only.]) ;;
|
||||
esac
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_LUKS_FORMAT], [$default_luks], [default LUKS format version])
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_CONFIG_FILES([ Makefile
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
* Document cryptsetup exit codes.
|
||||
|
||||
2011-03-18 Milan Broz <mbroz@redhat.com>
|
||||
* Respect maximum keyfile size paramater.
|
||||
* Respect maximum keyfile size parameter.
|
||||
* Introduce maximum default keyfile size, add configure option.
|
||||
* Require the whole key read from keyfile in create command (broken in 1.2.0).
|
||||
* Fix offset option for loopaesOpen.
|
||||
@@ -334,13 +334,13 @@
|
||||
* Version 1.1.0.
|
||||
|
||||
2010-01-10 Milan Broz <mbroz@redhat.com>
|
||||
* Fix initialisation of gcrypt duting luksFormat.
|
||||
* Convert hash name to lower case in header (fix sha1 backward comatible header)
|
||||
* Fix initialisation of gcrypt during luksFormat.
|
||||
* Convert hash name to lower case in header (fix sha1 backward compatible header)
|
||||
* Check for minimum required gcrypt version.
|
||||
|
||||
2009-12-30 Milan Broz <mbroz@redhat.com>
|
||||
* Fix key slot iteration count calculation (small -i value was the same as default).
|
||||
* The slot and key digest iteration minimun is now 1000.
|
||||
* The slot and key digest iteration minimum is now 1000.
|
||||
* The key digest iteration # is calculated from iteration time (approx 1/8 of that).
|
||||
* Version 1.1.0-rc4.
|
||||
|
||||
@@ -395,16 +395,16 @@
|
||||
* Require device device-mapper to build and do not use backend wrapper for dm calls.
|
||||
* Move memory locking and dm initialization to command layer.
|
||||
* Increase priority of process if memory is locked.
|
||||
* Add log macros and make logging modre consitent.
|
||||
* Add log macros and make logging more consistent.
|
||||
* Move command successful messages to verbose level.
|
||||
* Introduce --debug parameter.
|
||||
* Move device utils code and provide context parameter (for log).
|
||||
* Keyfile now must be provided by path, only stdin file descriptor is used (api only).
|
||||
* Do not call isatty() on closed keyfile descriptor.
|
||||
* Run performance check for PBKDF2 from LUKS code, do not mix hash algoritms results.
|
||||
* Run performance check for PBKDF2 from LUKS code, do not mix hash algorithms results.
|
||||
* Add ability to provide pre-generated master key and UUID in LUKS header format.
|
||||
* Add LUKS function to verify master key digest.
|
||||
* Move key slot manuipulation function into LUKS specific code.
|
||||
* Move key slot manipulation function into LUKS specific code.
|
||||
* Replace global options struct with separate parameters in helper functions.
|
||||
* Add new libcryptsetup API (documented in libcryptsetup.h).
|
||||
* Implement old API calls using new functions.
|
||||
@@ -412,7 +412,7 @@
|
||||
* Add --master-key-file option for luksFormat and luksAddKey.
|
||||
|
||||
2009-08-17 Milan Broz <mbroz@redhat.com>
|
||||
* Fix PBKDF2 speed calculation for large passhrases.
|
||||
* Fix PBKDF2 speed calculation for large passphrases.
|
||||
* Allow using passphrase provided in options struct for LuksOpen.
|
||||
* Allow restrict keys size in LuksOpen.
|
||||
|
||||
@@ -424,7 +424,7 @@
|
||||
* Switch PBKDF2 from internal SHA1 to libgcrypt, make hash algorithm not hardcoded to SHA1 here.
|
||||
* Add required parameters for changing hash used in LUKS key setup scheme.
|
||||
* Do not export simple XOR helper now used only inside AF functions.
|
||||
* Completely remove internal SHA1 implementanion code, not needed anymore.
|
||||
* Completely remove internal SHA1 implementation code, not needed anymore.
|
||||
* Enable hash algorithm selection for LUKS through -h luksFormat option.
|
||||
|
||||
2009-07-28 Milan Broz <mbroz@redhat.com>
|
||||
@@ -705,7 +705,7 @@
|
||||
|
||||
2005-12-06 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
|
||||
* man/cryptsetup.8: Correct "seconds" to "microseconds" in the explaination for -i.
|
||||
* man/cryptsetup.8: Correct "seconds" to "microseconds" in the explanation for -i.
|
||||
|
||||
2005-11-09 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
|
||||
@@ -726,7 +726,7 @@
|
||||
|
||||
2005-09-08 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
|
||||
* lib/setup.c (get_key): Fixed another incompatiblity with
|
||||
* lib/setup.c (get_key): Fixed another incompatibility with
|
||||
original cryptsetup.
|
||||
|
||||
2005-08-20 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
@@ -816,7 +816,7 @@
|
||||
|
||||
* man/cryptsetup.1: Add man page.
|
||||
|
||||
* lib/setup.c: Remove unneccessary LUKS_write_phdr call, so the
|
||||
* lib/setup.c: Remove unnecessary LUKS_write_phdr call, so the
|
||||
phdr is written after passphrase reading, so the user can change
|
||||
his mind, and not have a partial written LUKS header on it's disk.
|
||||
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
LUKS2 on-disk format
|
||||
====================
|
||||
|
||||
Note: these are temporary documentation notes only.
|
||||
The more formal definition will be published later.
|
||||
|
||||
Design goals
|
||||
~~~~~~~~~~~~
|
||||
The LUKS2 is an on-disk storage format designed to
|
||||
provide simple key management, primarily intended for Full Disk
|
||||
Encryption based on dm-crypt.
|
||||
|
||||
The LUKS2 is highly inspired by LUKS1 format and in some
|
||||
specific situations (most of the default installations) can be converted
|
||||
in-place (in both ways - to and from LUKS1).
|
||||
|
||||
The LUKS2 format is designed to allow future updates of various
|
||||
parts without the need to modify binary structures.
|
||||
|
||||
On-disk format provides redundancy of metadata, detection
|
||||
of metadata corruption and automatic repair from metadata copy.
|
||||
|
||||
NOTE: For security reasons, there is no redundancy in keyslots
|
||||
binary data (encrypted keys) but format allows updating to redundant
|
||||
keyslot encryption in future (add forward error correction codes
|
||||
is one possibility).
|
||||
|
||||
On-disk structure
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The LUKS2 header contains three parts:
|
||||
- binary header (one 4096 bytes sector)
|
||||
- area for metadata stored in JSON format
|
||||
- keyslot area (per-context binary data).
|
||||
|
||||
The binary header and JSON area are stored twice to increase
|
||||
redundancy. Keyslot area is allocated per-demand, and it is stored only once.
|
||||
|
||||
The basic on-disk structure is then
|
||||
|
||||
0 4096
|
||||
| bin hdr1 | JSON ... | bin hdr2 | JSON ... | Keyslot data | <padding> | (data payload)
|
||||
|
||||
Binary header
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The binary header is intended for quick scanning (by blkid and udev) and contains
|
||||
magic string to detect the device, basic information (labels), header size information
|
||||
and metadata checksum.
|
||||
Checksum covers both binary data and following JSON area and is calculated
|
||||
with checksum fields zeroed. By default plain SHA256 checksum is used.
|
||||
|
||||
The primary binary header is always stored in sector 0 of the device.
|
||||
|
||||
The C structure of binary header (see luks2.h) is
|
||||
|
||||
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
|
||||
#define LUKS2_MAGIC_2ND "SKUL\xba\xbe"
|
||||
#define LUKS2_MAGIC_L 6
|
||||
#define LUKS2_UUID_L 40
|
||||
#define LUKS2_LABEL_L 48
|
||||
#define LUKS2_SALT_L 64
|
||||
#define LUKS2_CHECKSUM_ALG_L 32
|
||||
#define LUKS2_CHECKSUM_L 64
|
||||
|
||||
struct luks2_hdr_disk {
|
||||
char magic[LUKS2_MAGIC_L]; /* "LUKS\xba\xbe" (1st) or "SKUL\xba\be" (2nd) */
|
||||
uint16_t version; /* Version 2 */
|
||||
uint64_t hdr_size; /* in bytes, including JSON area */
|
||||
uint64_t seqid; /* sequence ID, increased on every update */
|
||||
char label[LUKS2_LABEL_L]; /* ASCII label or empty */
|
||||
char checksum_alg[LUKS2_CHECKSUM_ALG_L]; /* checksum algorithm, "sha256" */
|
||||
uint8_t salt[LUKS2_SALT_L]; /* random salt, unique for every header */
|
||||
char uuid[LUKS2_UUID_L]; /* UUID of device */
|
||||
char subsystem[LUKS2_LABEL_L]; /* owner subsystem label or empty */
|
||||
uint64_t hdr_offset; /* header offset from device start in bytes */
|
||||
char _padding[184]; /* must be zeroed */
|
||||
uint8_t csum[LUKS2_CHECKSUM_L]; /* header checksum */
|
||||
char _padding4096[7*512]; /* must be zeroed */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
The LUKS1 compatible field (magic, UUID) are placed intentionally on the same offsets.
|
||||
The header version must be set to 2.
|
||||
The UUID is the same format as in LUKS1.
|
||||
|
||||
Magic string differs between the first and second header.
|
||||
|
||||
The hdr_offset must match physical header offset on the device.
|
||||
If hdr_offset does not match, the header is misplaced and must not be used.
|
||||
(It is a prevention to partition resize or manipulation with device start offset.)
|
||||
|
||||
The hdr_size contains the size of the binary header and JSON data area.
|
||||
The offset and size of the second (backup) header must match to these data.
|
||||
(Prevention to rewrite of a header with different JSON area size.)
|
||||
|
||||
There are two labels - label and subsystem. Content of these fields will be visible
|
||||
in UDEV/blkid scan and can be used for similar purposes as a filesystem label.
|
||||
These fields are by default empty.
|
||||
|
||||
The salt field in binary header is generated by an RNG and is different for
|
||||
every header, even the backup header must contain a different salt.
|
||||
The salt in binary header is not used after the header is read, the main intention
|
||||
is to avoid deduplication of the header sector.
|
||||
The salt must be regenerated on every header repair (but not on regular update).
|
||||
|
||||
The sequential number (seqid) is a counter that is always increased when a new
|
||||
update of the header is written. The header with higher seqid is more recent and
|
||||
is used for recovery (if there are two headers with different seqid, the
|
||||
more recent one is automatically used).
|
||||
|
||||
The rest of binary header must be zeroed.
|
||||
|
||||
JSON area
|
||||
~~~~~~~~~
|
||||
The JSON area starts immediately after the binary header. Its size is set
|
||||
by binary header hdr_size field (JSON area size = hdr_size - 4096).
|
||||
|
||||
The area contains metadata in JSON format and is fixed. Unused remainder
|
||||
of the area must be empty.
|
||||
|
||||
The header cannot store larger metadata that this fixed buffer and header
|
||||
size must be set properly during format. For now, only areas with 14 kB
|
||||
header (4kB binary header + 14kB JSON area) is created during format.
|
||||
|
||||
The JSON is structured to be able to describe system in very generic way,
|
||||
but LUKS2 intentionally limits options to values that are supportable
|
||||
in implemented version.
|
||||
|
||||
JSON structure is as follows:
|
||||
|
||||
Mandatory sections (must be present but some can be empty):
|
||||
- config
|
||||
- keyslots
|
||||
- digests
|
||||
- segments
|
||||
- tokens
|
||||
|
||||
Except for config section, all section contains array of objects that must be named
|
||||
as number (unsigned integer) - for example keyslot "0", "1" etc.
|
||||
Every object is typed (must contain attribute "type").
|
||||
According to type, library decides how to handle (or ignore) such an object.
|
||||
|
||||
Binary data inside JSON (for example salt) is stored in Hexa64 encoding.
|
||||
|
||||
If a value is needed to be stored as a 64bit integer (usually offset or size),
|
||||
it is stored in text format and later converted to the 64bit integer.
|
||||
(JSON cannot store 64bit integers directly.)
|
||||
|
||||
Config section
|
||||
~~~~~~~~~~~~~~
|
||||
Config contains information about JSON buffer size (cross-checked with binary header),
|
||||
keyslot area size and optional object with activation flags.
|
||||
|
||||
The "flags" section is array of activation flags that are automatically used
|
||||
when LUKS device is activated (for example it can unconditionally allow TRIM/discard
|
||||
functionality on the encrypted device).
|
||||
|
||||
Segments sections
|
||||
~~~~~~~~~~~~~~~~~
|
||||
The segment is an encrypted area on the disk containing data (in LUKS1 often
|
||||
mentioned as a data payload).
|
||||
For now, only one data area is available for the user.
|
||||
(More segments will be later used for on-line re-encryption functionality.)
|
||||
|
||||
Segments contain definition about encryption parameters, sector size and
|
||||
start and length of the segments. By default, the segment starts directly
|
||||
after the LUKS2 header and is marked as "dynamic" (it automatically detects
|
||||
the size of the available device).
|
||||
|
||||
Optionally it can contain information about data integrity protection,
|
||||
then the data segments is formatted as dm-integrity device and dm-crypt
|
||||
encryption is stacked above.
|
||||
|
||||
To activate a segment, there must be at least one digest linked to it.
|
||||
|
||||
Keyslots section
|
||||
~~~~~~~~~~~~~~~~
|
||||
Keyslot object contains information stored key - area, where it is stored
|
||||
(keyslot data), encryption, anti-forensic function, and Key Derivation Function
|
||||
and its parameters (PBKDF type, costs, salt).
|
||||
|
||||
For now, only internal "luks2" keyslot type is available, it uses the same logic
|
||||
as LUKS1 keyslot, but allows to define per-keyslot algorithms
|
||||
(for example different PBKDF).
|
||||
|
||||
Digests section
|
||||
~~~~~~~~~~~~~~~
|
||||
The digest is used to verify that volume key decrypted from a keyslot is correct.
|
||||
A digest is linked to keyslots and segment.
|
||||
|
||||
For now, only "pbkdf2" digest (LUKS1 compatible digest that uses PBKDF2)
|
||||
is supported.
|
||||
|
||||
Tokens section
|
||||
~~~~~~~~~~~~~~
|
||||
A token is an object that can describe "how to get passphrase or key" to unlock
|
||||
particular keyslot or it can be used t store any additional data (even unrelated
|
||||
to a keyslot).
|
||||
This area can be user configurable, and libcryptsetup provides interface to
|
||||
store used data directly in JSON format.
|
||||
Some token types are implemented internally, for now, there is only "luks2-keyring".
|
||||
type. This token type tries to load unlocking passphrase from kernel keyring
|
||||
with stored identification.
|
||||
|
||||
There can be external application that uses token objects to store metadata and
|
||||
implements bindings to specific hardware (TPM etc.).
|
||||
|
||||
LUKS2 JSON Format Example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
For illustration this is example of a LUKS2 device JSON:
|
||||
|
||||
{
|
||||
"keyslots":{
|
||||
"0":{
|
||||
"type":"luks2",
|
||||
"key_size":32,
|
||||
"kdf":{
|
||||
"type":"argon2i",
|
||||
"time":181,
|
||||
"memory":1024,
|
||||
"cpus":4,
|
||||
"salt":"Xfc5ScS8tCLrdbt6jtyWsBjCwAn3Msn\/enOYaAq8PEo="
|
||||
},
|
||||
"af":{
|
||||
"type":"luks1",
|
||||
"hash":"sha256",
|
||||
"stripes":4000
|
||||
},
|
||||
"area":{
|
||||
"type":"raw",
|
||||
"encryption":"aes-xts-plain64",
|
||||
"key_size":32,
|
||||
"offset":"32768",
|
||||
"size":"131072"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tokens":{
|
||||
"0":{
|
||||
"type":"luks2-keyring",
|
||||
"keyslots":[
|
||||
"0"
|
||||
],
|
||||
"key_description":"my-token"
|
||||
}
|
||||
},
|
||||
"segments":{
|
||||
"0":{
|
||||
"type":"crypt",
|
||||
"offset":"4194304",
|
||||
"iv_tweak":"0",
|
||||
"size":"dynamic",
|
||||
"encryption":"aes-xts-plain64",
|
||||
"sector_size":512
|
||||
}
|
||||
},
|
||||
"digests":{
|
||||
"0":{
|
||||
"type":"pbkdf2",
|
||||
"keyslots":[
|
||||
"0"
|
||||
],
|
||||
"segments":[
|
||||
"0"
|
||||
],
|
||||
"hash":"sha256",
|
||||
"iterations":155298,
|
||||
"salt":"WgMOideLECc5hfnmFVu3bwttJpkfnpf2RayE2WhP8zU=",
|
||||
"digest":"olobPk9pc0GItqofH78aMPmRaOZIbRevlvSlTZ91NLI="
|
||||
}
|
||||
},
|
||||
"config":{
|
||||
"json_size":"12288",
|
||||
"keyslots_size":"4161536",
|
||||
"flags":[
|
||||
"allow-discards"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@
|
||||
* @subsection cformat crypt_format() - header and payload on mutual device
|
||||
* This section covers basic use cases for formatting LUKS devices. Format operation
|
||||
* sets device type in context and in case of LUKS header is written at the beginning
|
||||
* of block device. In the example bellow we use the scenario where LUKS header and data
|
||||
* of block device. In the example below we use the scenario where LUKS header and data
|
||||
* are both stored on the same device. There's also a possibility to store header and
|
||||
* data separately.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* An example of using logging through libcryptsetup API
|
||||
*
|
||||
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* An example of using LUKS device through libcryptsetup API
|
||||
*
|
||||
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
BIN
docs/on-disk-format-luks2.pdf
Normal file
BIN
docs/on-disk-format-luks2.pdf
Normal file
Binary file not shown.
Binary file not shown.
@@ -15,7 +15,7 @@ Important changes
|
||||
* NSS (because of missing ripemd160 it cannot provide full backward compatibility)
|
||||
* kernel userspace API (provided by kernel 2.6.38 and above)
|
||||
(Note that kernel userspace backend is very slow for this type of operation.
|
||||
But it can be usefull for embedded systems, because you can avoid userspace
|
||||
But it can be useful for embedded systems, because you can avoid userspace
|
||||
crypto library completely.)
|
||||
|
||||
Backend is selected during configure time, using --with-crypto_backend option.
|
||||
|
||||
@@ -89,7 +89,7 @@ WARNING: This release removes old deprecated API from libcryptsetup
|
||||
(It can be used to simulate trivial hidden disk concepts.)
|
||||
|
||||
libcryptsetup API changes:
|
||||
* Added options to suport detached metadata device
|
||||
* Added options to support detached metadata device
|
||||
crypt_init_by_name_and_header()
|
||||
crypt_set_data_device()
|
||||
* Add crypt_last_error() API call.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Cryptsetup 2.0.0 RC1 Release Notes
|
||||
==================================
|
||||
Release candidate with experimental features.
|
||||
Cryptsetup 2.0.0 Release Notes
|
||||
==============================
|
||||
Stable release with experimental features.
|
||||
|
||||
This version introduces a new on-disk LUKS2 format.
|
||||
|
||||
@@ -12,18 +12,28 @@ major version for all public symbols.
|
||||
Most of the old functions are fully backward compatible, so only
|
||||
recompilation of programs should be needed.
|
||||
|
||||
Please note that authenticated disk encryption, noncryptographic
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
Please do not use it without properly configured backup or in
|
||||
production systems.
|
||||
|
||||
Until final 2.0 version is released, the new LUKS2 format
|
||||
could still internally change if a major problem is found.
|
||||
To provide all security features of authenticated encryption we need
|
||||
better nonce-reuse resistant algorithm in kernel (see note below).
|
||||
For now, please use authenticated encryption as experimental feature.
|
||||
|
||||
The library API calls (versioned symbols) are now stable and
|
||||
will not change in an incompatible way.
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.0-RC1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Limit KDF requested (for format) memory by available physical memory.
|
||||
On some systems too high requested amount of memory causes OOM killer
|
||||
to kill the process (instead of returning ENOMEM).
|
||||
We never try to use more than half of available physical memory.
|
||||
|
||||
* Ignore device alignment if it is not multiple of minimal-io.
|
||||
Some USB enclosures seems to report bogus topology info that
|
||||
prevents to use LUKS detached header.
|
||||
|
||||
Changes since version 2.0.0-RC0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -248,12 +258,13 @@ The newly added features in LUKS2 include:
|
||||
|
||||
For testing of authenticated encryption, these algorithms work for now:
|
||||
|
||||
1) aes-xts-random with hmac-sha256 or hmac-sha512 as the authentication tag.
|
||||
(Authentication key for HMAC is independently generated. This mode is very slow.)
|
||||
$ cryptsetup luksFormat --type luks2 <device> --cipher aes-xts-random --integrity hmac-sha256
|
||||
1) aes-xts-plain64 with hmac-sha256 or hmac-sha512 as the authentication tag.
|
||||
(Common FDE mode + independent authentication tag. Authentication key
|
||||
for HMAC is independently generated. This mode is very slow.)
|
||||
$ cryptsetup luksFormat --type luks2 <device> --cipher aes-xts-plain64 --integrity hmac-sha256
|
||||
|
||||
2) aes-gcm-random (native AEAD mode)
|
||||
DO NOT USE in production. The GCM mode uses only 96-bit nonce,
|
||||
DO NOT USE in production! The GCM mode uses only 96-bit nonce,
|
||||
and possible collision means fatal security problem.
|
||||
GCM mode has very good hardware support through AES-NI, so it is useful
|
||||
for performance testing.
|
||||
@@ -267,17 +278,8 @@ The newly added features in LUKS2 include:
|
||||
should work as well. The mode 1) and 2) should be compatible with IEEE 1619.1
|
||||
standard recommendation.
|
||||
|
||||
You can also store only random IV in tag without integrity protection.
|
||||
|
||||
Note that using random IV forces the system to pseudorandomly change the whole
|
||||
sector on every write without removing parallel processing of XTS mode.
|
||||
In cryptography, we can say that this will provide indistinguishability under
|
||||
chosen plaintext attack (IND-CPA) that cannot be achieved in legacy
|
||||
FDE systems. On the other side, if stored random IV is corrupted, the sector
|
||||
is no longer decrypted properly.
|
||||
|
||||
To use only random IV (no integrity protection), just specify "none" integrity.
|
||||
$ cryptsetup luksFormat --type luks2 <device> --cipher aes-xts-random --integrity none
|
||||
There will be better suitable authenticated modes available soon
|
||||
For now we are just preparing framework to enable it (and hopefully improve security of FDE).
|
||||
|
||||
FDE authenticated encryption is not a replacement for filesystem layer
|
||||
authenticated encryption. The goal is to provide at least something because
|
||||
@@ -296,7 +298,7 @@ The newly added features in LUKS2 include:
|
||||
To solve this problem, a new PBKDF, based on so-called memory-hard functions
|
||||
can be used. Key derivation with memory-hard function requires a certain
|
||||
amount of memory to compute its output. The memory requirement is very
|
||||
costly for GPUs and prevents these systems to operate ineffectively,
|
||||
costly for GPUs and prevents these systems to operate effectively,
|
||||
increasing cost for attackers.
|
||||
|
||||
LUKS2 introduces support for Argon2i and Argon2id as a PBKDF.
|
||||
@@ -481,7 +483,7 @@ Other changes
|
||||
For LUKS2 it is always better to specify full settings (do not rely on default
|
||||
cost values).
|
||||
For example, we can set to use Argon2id with iteration cost 5, memory 128000
|
||||
and paralell set 1:
|
||||
and parallel set 1:
|
||||
$ cryptsetup luksFormat --type luks2 <device> \
|
||||
--pbkdf argon2id --pbkdf-force-iterations 5 --pbkdf-memory 128000 --pbkdf-parallel 1
|
||||
|
||||
@@ -565,21 +567,24 @@ These new calls are now exported, for details see libcryptsetup.h:
|
||||
crypt_keyfile_read;
|
||||
crypt_wipe;
|
||||
|
||||
Unfinished things & TODO for next RC or future
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* There will be better documentation and examples.
|
||||
|
||||
* There will be some more formal definition of the threat model for integrity
|
||||
protection. (And a link to some papers discussing integrity protection,
|
||||
once it is, hopefully, accepted and published.)
|
||||
|
||||
* Offline re-encrypt tool supports only LUKS1 format for now (patches are
|
||||
on the way).
|
||||
* Offline re-encrypt tool LUKS2 support is currently limited.
|
||||
There will be online LUKS2 re-encryption tool in future.
|
||||
|
||||
* There will be online LUKS2 re-encryption tool in future.
|
||||
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition,
|
||||
once these algorithms are available in kernel.
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
(https://competitions.cr.yp.to/caesar.html) once these algorithms are available
|
||||
in kernel (more on this later).
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collison probability is not negligible).
|
||||
For the GCM, nonce collision is a fatal problem.
|
||||
|
||||
* Authenticated encryption do not set encryption for dm-integrity journal.
|
||||
|
||||
@@ -588,17 +593,13 @@ Unfinished things & TODO for next RC or future
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* Some utilities (blkid, systemd-cryptsetup) will need small updates to support
|
||||
LUKS2 format.
|
||||
* Some utilities (blkid, systemd-cryptsetup) have already support for LUKS
|
||||
but not yet in released version (support in crypttab etc).
|
||||
|
||||
* There are some examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
We will document these examples later in release notes for next RC.
|
||||
|
||||
* The distribution archive is now very big because of some testing images that do not compress
|
||||
well. Some cleaning is needed here.
|
||||
|
||||
* A lot of ideas are hidden inside the LUKS2 design that is not yet used or
|
||||
described here, let's try if the basics work first :-)
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be deprecated soon in favor
|
||||
of python bindings to libblockdev library (that can already handle LUKS1 devices).
|
||||
109
docs/v2.0.1-ReleaseNotes
Normal file
109
docs/v2.0.1-ReleaseNotes
Normal file
@@ -0,0 +1,109 @@
|
||||
Cryptsetup 2.0.1 Release Notes
|
||||
==============================
|
||||
Stable and bug-fix release with experimental features.
|
||||
|
||||
This version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
To provide all security features of authenticated encryption we need
|
||||
a better nonce-reuse resistant algorithm in the kernel (see note below).
|
||||
For now, please use authenticated encryption as an experimental feature.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* To store volume key into kernel keyring, kernel 4.15 with dm-crypt 1.18.1
|
||||
is required. If a volume key is stored in keyring (LUKS2 only),
|
||||
the dm-crypt v1.15.0 through v1.18.0 contains a serious bug that may cause
|
||||
data corruption for ciphers with ESSIV.
|
||||
(The key for ESSIV is zeroed because of code misplacement.)
|
||||
This bug is not present for LUKS1 or any other IVs used in LUKS modes.
|
||||
This change is not visible to the user (except dmsetup output).
|
||||
|
||||
* Increase maximum allowed PBKDF memory-cost limit to 4 GiB.
|
||||
The Argon2 PBKDF uses 1GiB by default; this is also limited by the amount
|
||||
of physical memory available (maximum is half of the physical memory).
|
||||
|
||||
* Use /run/cryptsetup as default for cryptsetup locking dir.
|
||||
There were problems with sharing /run/lock with lockdev, and in the early
|
||||
boot, the directory was missing.
|
||||
The directory can be changed with --with-luks2-lock-path and
|
||||
--with-luks2-lock-dir-perms configure switches.
|
||||
|
||||
* Introduce new 64-bit byte-offset *keyfile_device_offset functions.
|
||||
|
||||
The keyfile interface was designed, well, for keyfiles. Unfortunately,
|
||||
there are user cases where a keyfile can be placed on a device, and
|
||||
size_t offset can overflow on 32-bit systems.
|
||||
|
||||
New set of functions that allow 64-bit offsets even on 32bit systems
|
||||
are now available:
|
||||
|
||||
- crypt_resume_by_keyfile_device_offset
|
||||
- crypt_keyslot_add_by_keyfile_device_offset
|
||||
- crypt_activate_by_keyfile_device_offset
|
||||
- crypt_keyfile_device_read
|
||||
|
||||
The new functions have added the _device_ in name.
|
||||
Old functions are just internal wrappers around these.
|
||||
|
||||
Also cryptsetup --keyfile-offset and --new-keyfile-offset now allows
|
||||
64-bit offsets as parameters.
|
||||
|
||||
* Add error hint for wrongly formatted cipher strings in LUKS1 and
|
||||
properly fail in luksFormat if cipher format is missing required IV.
|
||||
For now, crypto API quietly used cipher without IV if a cipher
|
||||
algorithm without IV specification was used (e.g., aes-xts).
|
||||
This caused fail later during activation.
|
||||
|
||||
* Configure check for a recent Argon2 lib to support mandatory Argon2id.
|
||||
|
||||
* Fix for the cryptsetup-reencrypt static build if pwquality is enabled.
|
||||
|
||||
* Update LUKS1 standard doc (https links in the bibliography).
|
||||
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* There will be better documentation and examples.
|
||||
|
||||
* There will be some more formal definition of the threat model for integrity
|
||||
protection. (And a link to some papers discussing integrity protection,
|
||||
once it is, hopefully, accepted and published.)
|
||||
|
||||
* Offline re-encrypt tool LUKS2 support is currently limited.
|
||||
There will be online LUKS2 re-encryption tool in future.
|
||||
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
(https://competitions.cr.yp.to/caesar.html) once these algorithms are
|
||||
available in the kernel (more on this later).
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in the kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collision probability is not negligible).
|
||||
For the GCM, nonce collision is a fatal problem.
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be deprecated soon in favor
|
||||
of python bindings to the libblockdev library (that can already handle LUKS1
|
||||
devices).
|
||||
93
docs/v2.0.2-ReleaseNotes
Normal file
93
docs/v2.0.2-ReleaseNotes
Normal file
@@ -0,0 +1,93 @@
|
||||
Cryptsetup 2.0.2 Release Notes
|
||||
==============================
|
||||
Stable and bug-fix release with experimental features.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
To provide all security features of authenticated encryption, we need
|
||||
a better nonce-reuse resistant algorithm in the kernel (see note below).
|
||||
For now, please use authenticated encryption as an experimental feature.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Fix a regression in early detection of inactive keyslot for luksKillSlot.
|
||||
It tried to ask for passphrase even for already erased keyslot.
|
||||
|
||||
* Fix a regression in loopaesOpen processing for keyfile on standard input.
|
||||
Use of "-" argument was not working properly.
|
||||
|
||||
* Add LUKS2 specific options for cryptsetup-reencrypt.
|
||||
Tokens and persistent flags are now transferred during reencryption;
|
||||
change of PBKDF keyslot parameters is now supported and allows
|
||||
to set precalculated values (no benchmarks).
|
||||
|
||||
* Do not allow LUKS2 --persistent and --test-passphrase cryptsetup flags
|
||||
combination. Persistent flags are now stored only if the device was
|
||||
successfully activated with the specified flags.
|
||||
|
||||
* Fix integritysetup format after recent Linux kernel changes that
|
||||
requires to setup key for HMAC in all cases.
|
||||
Previously integritysetup allowed HMAC with zero key that behaves
|
||||
like a plain hash.
|
||||
|
||||
* Fix VeraCrypt PIM handling that modified internal iteration counts
|
||||
even for subsequent activations. The PIM count is no longer printed
|
||||
in debug log as it is sensitive information.
|
||||
Also, the code now skips legacy TrueCrypt algorithms if a PIM
|
||||
is specified (they cannot be used with PIM anyway).
|
||||
|
||||
* PBKDF values cannot be set (even with force parameters) below
|
||||
hardcoded minimums. For PBKDF2 is it 1000 iterations, for Argon2
|
||||
it is 4 iterations and 32 KiB of memory cost.
|
||||
|
||||
* Introduce new crypt_token_is_assigned() API function for reporting
|
||||
the binding between token and keyslots.
|
||||
|
||||
* Allow crypt_token_json_set() API function to create internal token types.
|
||||
Do not allow unknown fields in internal token objects.
|
||||
|
||||
* Print message in cryptsetup that about was aborted if a user did not
|
||||
answer YES in a query.
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* There will be better documentation and examples.
|
||||
|
||||
* There will be some more formal definition of the threat model for integrity
|
||||
protection. (And a link to some papers discussing integrity protection,
|
||||
once it is, hopefully, accepted and published.)
|
||||
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
We plan to use AEGIS and MORUS, as CAESAR finalists.
|
||||
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in the kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collision probability is not negligible).
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be deprecated in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
121
docs/v2.0.3-ReleaseNotes
Normal file
121
docs/v2.0.3-ReleaseNotes
Normal file
@@ -0,0 +1,121 @@
|
||||
Cryptsetup 2.0.3 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release with new features.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
To provide all security features of authenticated encryption, we need
|
||||
a better nonce-reuse resistant algorithm in the kernel (see note below).
|
||||
For now, please use authenticated encryption as an experimental feature.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Expose interface to unbound LUKS2 keyslots.
|
||||
Unbound LUKS2 keyslot allows storing a key material that is independent
|
||||
of master volume key (it is not bound to encrypted data segment).
|
||||
|
||||
* New API extensions for unbound keyslots (LUKS2 only)
|
||||
crypt_keyslot_get_key_size() and crypt_volume_key_get()
|
||||
These functions allow to get key and key size for unbound keyslots.
|
||||
|
||||
* New enum value CRYPT_SLOT_UNBOUND for keyslot status (LUKS2 only).
|
||||
|
||||
* Add --unbound keyslot option to the cryptsetup luksAddKey command.
|
||||
|
||||
* Add crypt_get_active_integrity_failures() call to get integrity
|
||||
failure count for dm-integrity devices.
|
||||
|
||||
* Add crypt_get_pbkdf_default() function to get per-type PBKDF default
|
||||
setting.
|
||||
|
||||
* Add new flag to crypt_keyslot_add_by_key() to force update device
|
||||
volume key. This call is mainly intended for a wrapped key change.
|
||||
|
||||
* Allow volume key store in a file with cryptsetup.
|
||||
The --dump-master-key together with --master-key-file allows cryptsetup
|
||||
to store the binary volume key to a file instead of standard output.
|
||||
|
||||
* Add support detached header for cryptsetup-reencrypt command.
|
||||
|
||||
* Fix VeraCrypt PIM handling - use proper iterations count formula
|
||||
for PBKDF2-SHA512 and PBKDF2-Whirlpool used in system volumes.
|
||||
|
||||
* Fix cryptsetup tcryptDump for VeraCrypt PIM (support --veracrypt-pim).
|
||||
|
||||
* Add --with-default-luks-format configure time option.
|
||||
(Option to override default LUKS format version.)
|
||||
|
||||
* Fix LUKS version conversion for detached (and trimmed) LUKS headers.
|
||||
|
||||
* Add luksConvertKey cryptsetup command that converts specific keyslot
|
||||
from one PBKDF to another.
|
||||
|
||||
* Do not allow conversion to LUKS2 if LUKSMETA (external tool metadata)
|
||||
header is detected.
|
||||
|
||||
* More cleanup and hardening of LUKS2 keyslot specific validation options.
|
||||
Add more checks for cipher validity before writing metadata on-disk.
|
||||
|
||||
* Do not allow LUKS1 version downconversion if the header contains tokens.
|
||||
|
||||
* Add "paes" family ciphers (AES wrapped key scheme for mainframes)
|
||||
to allowed ciphers.
|
||||
Specific wrapped ley configuration logic must be done by 3rd party tool,
|
||||
LUKS2 stores only keyslot material and allow activation of the device.
|
||||
|
||||
* Add support for --check-at-most-once option (kernel 4.17) to veritysetup.
|
||||
This flag can be dangerous; if you can control underlying device
|
||||
(you can change its content after it was verified) it will no longer
|
||||
prevent reading tampered data and also it does not prevent silent
|
||||
data corruptions that appear after the block was once read.
|
||||
|
||||
* Fix return code (EPERM instead of EINVAL) and retry count for bad
|
||||
passphrase on non-tty input.
|
||||
|
||||
* Enable support for FEC decoding in veritysetup to check dm-verity devices
|
||||
with additional Reed-Solomon code in userspace (verify command).
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* There will be better documentation and examples (planned for 2.0.4).
|
||||
|
||||
* There will be some more formal definition of the threat model for integrity
|
||||
protection. (And a link to some papers discussing integrity protection,
|
||||
once it is, hopefully, accepted and published.)
|
||||
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
We plan to use AEGIS and MORUS, as CAESAR finalists.
|
||||
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in the kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collision probability is not negligible).
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be REMOVED in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
See https://github.com/storaged-project/libblockdev/releases/tag/2.17-1 that
|
||||
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.
|
||||
119
docs/v2.0.4-ReleaseNotes
Normal file
119
docs/v2.0.4-ReleaseNotes
Normal file
@@ -0,0 +1,119 @@
|
||||
Cryptsetup 2.0.4 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release with new features.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
To provide all security features of authenticated encryption, we need
|
||||
a better nonce-reuse resistant algorithm in the kernel (see note below).
|
||||
For now, please use authenticated encryption as an experimental feature.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.3
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Use the libblkid (blockid) library to detect foreign signatures
|
||||
on a device before LUKS format and LUKS2 auto-recovery.
|
||||
|
||||
This change fixes an unexpected recovery using the secondary
|
||||
LUKS2 header after a device was already overwritten with
|
||||
another format (filesystem or LVM physical volume).
|
||||
|
||||
LUKS2 will not recreate a primary header if it detects a valid
|
||||
foreign signature. In this situation, a user must always
|
||||
use cryptsetup repair command for the recovery.
|
||||
|
||||
Note that libcryptsetup and utilities are now linked to libblkid
|
||||
as a new dependence.
|
||||
|
||||
To compile code without blockid support (strongly discouraged),
|
||||
use --disable-blkid configure switch.
|
||||
|
||||
* Add prompt for format and repair actions in cryptsetup and
|
||||
integritysetup if foreign signatures are detected on the device
|
||||
through the blockid library.
|
||||
|
||||
After the confirmation, all known signatures are then wiped as
|
||||
part of the format or repair procedure.
|
||||
|
||||
* Print consistent verbose message about keyslot and token numbers.
|
||||
For keyslot actions: Key slot <number> unlocked/created/removed.
|
||||
For token actions: Token <number> created/removed.
|
||||
|
||||
* Print error, if a non-existent token is tried to be removed.
|
||||
|
||||
* Add support for LUKS2 token definition export and import.
|
||||
|
||||
The token command now can export/import customized token JSON file
|
||||
directly from command line. See the man page for more details.
|
||||
|
||||
* Add support for new dm-integrity superblock version 2.
|
||||
|
||||
* Add an error message when nothing was read from a key file.
|
||||
|
||||
* Update cryptsetup man pages, including --type option usage.
|
||||
|
||||
* Add a snapshot of LUKS2 format specification to documentation
|
||||
and accordingly fix supported secondary header offsets.
|
||||
|
||||
* Add bundled optimized Argon2 SSE (X86_64 platform) code.
|
||||
|
||||
If the bundled Argon2 code is used and the new configure switch
|
||||
--enable-internal-sse-argon2 option is present, and compiler flags
|
||||
support required optimization, the code will try to use optimized
|
||||
and faster variant.
|
||||
|
||||
Always use the shared library (--enable-libargon2) if possible.
|
||||
|
||||
This option was added because an enterprise distribution
|
||||
rejected to support the shared Argon2 library and native support
|
||||
in generic cryptographic libraries is not ready yet.
|
||||
|
||||
* Fix compilation with crypto backend for LibreSSL >= 2.7.0.
|
||||
LibreSSL introduced OpenSSL 1.1.x API functions, so compatibility
|
||||
wrapper must be commented out.
|
||||
|
||||
* Fix on-disk header size calculation for LUKS2 format if a specific
|
||||
data alignment is requested. Until now, the code used default size
|
||||
that could be wrong for converted devices.
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
We plan to use AEGIS and MORUS (in kernel 4.18), as CAESAR finalists.
|
||||
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in the kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collision probability is not negligible).
|
||||
|
||||
For more info about LUKS2 authenticated encryption, please see our paper
|
||||
https://arxiv.org/abs/1807.00309
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be REMOVED in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
See https://github.com/storaged-project/libblockdev/releases that
|
||||
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.
|
||||
|
||||
@@ -3,10 +3,18 @@ pkgconfig_DATA = lib/libcryptsetup.pc
|
||||
|
||||
lib_LTLIBRARIES = libcryptsetup.la
|
||||
|
||||
noinst_LTLIBRARIES += libutils_io.la
|
||||
|
||||
include_HEADERS = lib/libcryptsetup.h
|
||||
|
||||
EXTRA_DIST += lib/libcryptsetup.pc.in lib/libcryptsetup.sym
|
||||
|
||||
libutils_io_la_CFLAGS = $(AM_CFLAGS)
|
||||
|
||||
libutils_io_la_SOURCES = \
|
||||
lib/utils_io.c \
|
||||
lib/utils_io.h
|
||||
|
||||
libcryptsetup_la_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
-I $(top_srcdir)/lib/crypto_backend \
|
||||
-I $(top_srcdir)/lib/luks1 \
|
||||
@@ -16,7 +24,7 @@ libcryptsetup_la_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
-I $(top_srcdir)/lib/tcrypt \
|
||||
-I $(top_srcdir)/lib/integrity
|
||||
|
||||
libcryptsetup_la_DEPENDENCIES = libcrypto_backend.la lib/libcryptsetup.sym
|
||||
libcryptsetup_la_DEPENDENCIES = libutils_io.la libcrypto_backend.la lib/libcryptsetup.sym
|
||||
|
||||
libcryptsetup_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \
|
||||
-Wl,--version-script=$(top_srcdir)/lib/libcryptsetup.sym \
|
||||
@@ -30,7 +38,9 @@ libcryptsetup_la_LIBADD = \
|
||||
@CRYPTO_LIBS@ \
|
||||
@LIBARGON2_LIBS@ \
|
||||
@JSON_C_LIBS@ \
|
||||
libcrypto_backend.la
|
||||
@BLKID_LIBS@ \
|
||||
libcrypto_backend.la \
|
||||
libutils_io.la
|
||||
|
||||
libcryptsetup_la_SOURCES = \
|
||||
lib/setup.c \
|
||||
@@ -77,6 +87,7 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/verity/verity.c \
|
||||
lib/verity/verity.h \
|
||||
lib/verity/rs_encode_char.c \
|
||||
lib/verity/rs_decode_char.c \
|
||||
lib/verity/rs.h \
|
||||
lib/luks2/luks2_disk_metadata.c \
|
||||
lib/luks2/luks2_json_format.c \
|
||||
@@ -89,4 +100,6 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/luks2/luks2_token_keyring.c \
|
||||
lib/luks2/luks2_token.c \
|
||||
lib/luks2/luks2_internal.h \
|
||||
lib/luks2/luks2.h
|
||||
lib/luks2/luks2.h \
|
||||
lib/utils_blkid.c \
|
||||
lib/utils_blkid.h
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* base64.c -- Encode binary data using printable characters.
|
||||
Copyright (C) 1999-2001, 2004-2006, 2009-2017 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999-2001, 2004-2006, 2009-2018 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -12,13 +12,13 @@
|
||||
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, see <http://www.gnu.org/licenses/>. */
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
|
||||
* (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
|
||||
* from Paul Eggert, Bruno Haible, and Stepan Kasal.
|
||||
*
|
||||
* See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>.
|
||||
* See also RFC 4648 <https://www.ietf.org/rfc/rfc4648.txt>.
|
||||
*
|
||||
* Be careful with error checking. Here is how you would typically
|
||||
* use these functions:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* base64.h -- Encode binary data using printable characters.
|
||||
Copyright (C) 2004-2006, 2009-2017 Free Software Foundation, Inc.
|
||||
Copyright (C) 2004-2006, 2009-2018 Free Software Foundation, Inc.
|
||||
Written by Simon Josefsson.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -13,7 +13,7 @@
|
||||
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, see <http://www.gnu.org/licenses/>. */
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef BASE64_H
|
||||
# define BASE64_H
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* cryptsetup plain device helper functions
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -8,7 +8,8 @@ libcrypto_backend_la_SOURCES = \
|
||||
lib/crypto_backend/crypto_storage.c \
|
||||
lib/crypto_backend/pbkdf_check.c \
|
||||
lib/crypto_backend/crc32.c \
|
||||
lib/crypto_backend/argon2_generic.c
|
||||
lib/crypto_backend/argon2_generic.c \
|
||||
lib/crypto_backend/cipher_generic.c
|
||||
|
||||
if CRYPTO_BACKEND_GCRYPT
|
||||
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_gcrypt.c
|
||||
|
||||
@@ -1,21 +1,30 @@
|
||||
noinst_LTLIBRARIES += libargon2.la
|
||||
|
||||
libargon2_la_CFLAGS = $(AM_CFLAGS) -std=c89 -pthread -O3
|
||||
libargon2_la_CPPFLAGS = $(AM_CPPFLAGS) -I lib/crypto_backend/argon2/blake2
|
||||
libargon2_la_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
-I lib/crypto_backend/argon2 \
|
||||
-I lib/crypto_backend/argon2/blake2
|
||||
|
||||
libargon2_la_SOURCES = \
|
||||
lib/crypto_backend/argon2/blake2/blake2b.c \
|
||||
lib/crypto_backend/argon2/blake2/blake2.h \
|
||||
lib/crypto_backend/argon2/blake2/blake2-impl.h \
|
||||
lib/crypto_backend/argon2/blake2/blamka-round-ref.h \
|
||||
lib/crypto_backend/argon2/argon2.c \
|
||||
lib/crypto_backend/argon2/argon2.h \
|
||||
lib/crypto_backend/argon2/core.c \
|
||||
lib/crypto_backend/argon2/core.h \
|
||||
lib/crypto_backend/argon2/encoding.c \
|
||||
lib/crypto_backend/argon2/encoding.h \
|
||||
lib/crypto_backend/argon2/ref.c \
|
||||
lib/crypto_backend/argon2/thread.c \
|
||||
lib/crypto_backend/argon2/thread.h
|
||||
|
||||
if CRYPTO_INTERNAL_SSE_ARGON2
|
||||
libargon2_la_SOURCES += lib/crypto_backend/argon2/blake2/blamka-round-opt.h \
|
||||
lib/crypto_backend/argon2/opt.c
|
||||
else
|
||||
libargon2_la_SOURCES += lib/crypto_backend/argon2/blake2/blamka-round-ref.h \
|
||||
lib/crypto_backend/argon2/ref.c
|
||||
endif
|
||||
|
||||
EXTRA_DIST += lib/crypto_backend/argon2/LICENSE
|
||||
EXTRA_DIST += lib/crypto_backend/argon2/README
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "encoding.h"
|
||||
#include "core.h"
|
||||
|
||||
/* to silent gcc -Wcast-qual for const cast */
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
|
||||
const char *argon2_type2string(argon2_type type, int uppercase) {
|
||||
switch (type) {
|
||||
case Argon2_d:
|
||||
@@ -283,7 +286,7 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ctx.pwd = (uint8_t *)pwd;
|
||||
ctx.pwd = CONST_CAST(uint8_t *)pwd;
|
||||
ctx.pwdlen = (uint32_t)pwdlen;
|
||||
|
||||
ret = decode_string(&ctx, encoded, type);
|
||||
@@ -346,7 +349,7 @@ int argon2_verify_ctx(argon2_context *context, const char *hash,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (argon2_compare((uint8_t *)hash, context->out, context->outlen)) {
|
||||
if (argon2_compare(CONST_CAST(uint8_t *)hash, context->out, context->outlen)) {
|
||||
return ARGON2_VERIFY_MISMATCH;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,13 @@ extern "C" {
|
||||
/* Symbols visibility control */
|
||||
#ifdef A2_VISCTL
|
||||
#define ARGON2_PUBLIC __attribute__((visibility("default")))
|
||||
#define ARGON2_LOCAL __attribute__ ((visibility ("hidden")))
|
||||
#elif _MSC_VER
|
||||
#define ARGON2_PUBLIC __declspec(dllexport)
|
||||
#define ARGON2_LOCAL
|
||||
#else
|
||||
#define ARGON2_PUBLIC
|
||||
#define ARGON2_LOCAL
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -90,7 +93,7 @@ extern "C" {
|
||||
#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1)
|
||||
|
||||
/* Global flag to determine if we are wiping internal memory buffers. This flag
|
||||
* is defined in core.c and deafults to 1 (wipe internal memory). */
|
||||
* is defined in core.c and defaults to 1 (wipe internal memory). */
|
||||
extern int FLAG_clear_internal_memory;
|
||||
|
||||
/* Error codes */
|
||||
|
||||
@@ -151,6 +151,4 @@ static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) {
|
||||
return (w >> c) | (w << (64 - c));
|
||||
}
|
||||
|
||||
void clear_internal_memory(void *v, size_t n);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
#ifndef PORTABLE_BLAKE2_H
|
||||
#define PORTABLE_BLAKE2_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "../argon2.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
@@ -69,19 +67,19 @@ enum {
|
||||
};
|
||||
|
||||
/* Streaming API */
|
||||
int blake2b_init(blake2b_state *S, size_t outlen);
|
||||
int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
|
||||
ARGON2_LOCAL int blake2b_init(blake2b_state *S, size_t outlen);
|
||||
ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
|
||||
size_t keylen);
|
||||
int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
|
||||
int blake2b_update(blake2b_state *S, const void *in, size_t inlen);
|
||||
int blake2b_final(blake2b_state *S, void *out, size_t outlen);
|
||||
ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
|
||||
ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, size_t inlen);
|
||||
ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, size_t outlen);
|
||||
|
||||
/* Simple API */
|
||||
int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
|
||||
const void *key, size_t keylen);
|
||||
ARGON2_LOCAL int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
|
||||
const void *key, size_t keylen);
|
||||
|
||||
/* Argon2 Team - Begin Code */
|
||||
int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);
|
||||
ARGON2_LOCAL int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);
|
||||
/* Argon2 Team - End Code */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "blake2.h"
|
||||
#include "blake2-impl.h"
|
||||
|
||||
void clear_internal_memory(void *v, size_t n);
|
||||
|
||||
static const uint64_t blake2b_IV[8] = {
|
||||
UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b),
|
||||
UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1),
|
||||
|
||||
471
lib/crypto_backend/argon2/blake2/blamka-round-opt.h
Normal file
471
lib/crypto_backend/argon2/blake2/blamka-round-opt.h
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#ifndef BLAKE_ROUND_MKA_OPT_H
|
||||
#define BLAKE_ROUND_MKA_OPT_H
|
||||
|
||||
#include "blake2-impl.h"
|
||||
|
||||
#include <emmintrin.h>
|
||||
#if defined(__SSSE3__)
|
||||
#include <tmmintrin.h> /* for _mm_shuffle_epi8 and _mm_alignr_epi8 */
|
||||
#endif
|
||||
|
||||
#if defined(__XOP__) && (defined(__GNUC__) || defined(__clang__))
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__AVX512F__)
|
||||
#if !defined(__AVX2__)
|
||||
#if !defined(__XOP__)
|
||||
#if defined(__SSSE3__)
|
||||
#define r16 \
|
||||
(_mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))
|
||||
#define r24 \
|
||||
(_mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))
|
||||
#define _mm_roti_epi64(x, c) \
|
||||
(-(c) == 32) \
|
||||
? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) \
|
||||
: (-(c) == 24) \
|
||||
? _mm_shuffle_epi8((x), r24) \
|
||||
: (-(c) == 16) \
|
||||
? _mm_shuffle_epi8((x), r16) \
|
||||
: (-(c) == 63) \
|
||||
? _mm_xor_si128(_mm_srli_epi64((x), -(c)), \
|
||||
_mm_add_epi64((x), (x))) \
|
||||
: _mm_xor_si128(_mm_srli_epi64((x), -(c)), \
|
||||
_mm_slli_epi64((x), 64 - (-(c))))
|
||||
#else /* defined(__SSE2__) */
|
||||
#define _mm_roti_epi64(r, c) \
|
||||
_mm_xor_si128(_mm_srli_epi64((r), -(c)), _mm_slli_epi64((r), 64 - (-(c))))
|
||||
#endif
|
||||
#else
|
||||
#endif
|
||||
|
||||
static BLAKE2_INLINE __m128i fBlaMka(__m128i x, __m128i y) {
|
||||
const __m128i z = _mm_mul_epu32(x, y);
|
||||
return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z));
|
||||
}
|
||||
|
||||
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = fBlaMka(A0, B0); \
|
||||
A1 = fBlaMka(A1, B1); \
|
||||
\
|
||||
D0 = _mm_xor_si128(D0, A0); \
|
||||
D1 = _mm_xor_si128(D1, A1); \
|
||||
\
|
||||
D0 = _mm_roti_epi64(D0, -32); \
|
||||
D1 = _mm_roti_epi64(D1, -32); \
|
||||
\
|
||||
C0 = fBlaMka(C0, D0); \
|
||||
C1 = fBlaMka(C1, D1); \
|
||||
\
|
||||
B0 = _mm_xor_si128(B0, C0); \
|
||||
B1 = _mm_xor_si128(B1, C1); \
|
||||
\
|
||||
B0 = _mm_roti_epi64(B0, -24); \
|
||||
B1 = _mm_roti_epi64(B1, -24); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = fBlaMka(A0, B0); \
|
||||
A1 = fBlaMka(A1, B1); \
|
||||
\
|
||||
D0 = _mm_xor_si128(D0, A0); \
|
||||
D1 = _mm_xor_si128(D1, A1); \
|
||||
\
|
||||
D0 = _mm_roti_epi64(D0, -16); \
|
||||
D1 = _mm_roti_epi64(D1, -16); \
|
||||
\
|
||||
C0 = fBlaMka(C0, D0); \
|
||||
C1 = fBlaMka(C1, D1); \
|
||||
\
|
||||
B0 = _mm_xor_si128(B0, C0); \
|
||||
B1 = _mm_xor_si128(B1, C1); \
|
||||
\
|
||||
B0 = _mm_roti_epi64(B0, -63); \
|
||||
B1 = _mm_roti_epi64(B1, -63); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#if defined(__SSSE3__)
|
||||
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0 = _mm_alignr_epi8(B1, B0, 8); \
|
||||
__m128i t1 = _mm_alignr_epi8(B0, B1, 8); \
|
||||
B0 = t0; \
|
||||
B1 = t1; \
|
||||
\
|
||||
t0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = t0; \
|
||||
\
|
||||
t0 = _mm_alignr_epi8(D1, D0, 8); \
|
||||
t1 = _mm_alignr_epi8(D0, D1, 8); \
|
||||
D0 = t1; \
|
||||
D1 = t0; \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0 = _mm_alignr_epi8(B0, B1, 8); \
|
||||
__m128i t1 = _mm_alignr_epi8(B1, B0, 8); \
|
||||
B0 = t0; \
|
||||
B1 = t1; \
|
||||
\
|
||||
t0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = t0; \
|
||||
\
|
||||
t0 = _mm_alignr_epi8(D0, D1, 8); \
|
||||
t1 = _mm_alignr_epi8(D1, D0, 8); \
|
||||
D0 = t1; \
|
||||
D1 = t0; \
|
||||
} while ((void)0, 0)
|
||||
#else /* SSE2 */
|
||||
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0 = D0; \
|
||||
__m128i t1 = B0; \
|
||||
D0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = D0; \
|
||||
D0 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t0, t0)); \
|
||||
D1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(D1, D1)); \
|
||||
B0 = _mm_unpackhi_epi64(B0, _mm_unpacklo_epi64(B1, B1)); \
|
||||
B1 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(t1, t1)); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0, t1; \
|
||||
t0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = t0; \
|
||||
t0 = B0; \
|
||||
t1 = D0; \
|
||||
B0 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(B0, B0)); \
|
||||
B1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(B1, B1)); \
|
||||
D0 = _mm_unpackhi_epi64(D0, _mm_unpacklo_epi64(D1, D1)); \
|
||||
D1 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t1, t1)); \
|
||||
} while ((void)0, 0)
|
||||
#endif
|
||||
|
||||
#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
} while ((void)0, 0)
|
||||
#else /* __AVX2__ */
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
#define rotr32(x) _mm256_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1))
|
||||
#define rotr24(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))
|
||||
#define rotr16(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))
|
||||
#define rotr63(x) _mm256_xor_si256(_mm256_srli_epi64((x), 63), _mm256_add_epi64((x), (x)))
|
||||
|
||||
#define G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i ml = _mm256_mul_epu32(A0, B0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
|
||||
D0 = _mm256_xor_si256(D0, A0); \
|
||||
D0 = rotr32(D0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C0, D0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
|
||||
\
|
||||
B0 = _mm256_xor_si256(B0, C0); \
|
||||
B0 = rotr24(B0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(A1, B1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
|
||||
D1 = _mm256_xor_si256(D1, A1); \
|
||||
D1 = rotr32(D1); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C1, D1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
|
||||
\
|
||||
B1 = _mm256_xor_si256(B1, C1); \
|
||||
B1 = rotr24(B1); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i ml = _mm256_mul_epu32(A0, B0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
|
||||
D0 = _mm256_xor_si256(D0, A0); \
|
||||
D0 = rotr16(D0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C0, D0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
|
||||
B0 = _mm256_xor_si256(B0, C0); \
|
||||
B0 = rotr63(B0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(A1, B1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
|
||||
D1 = _mm256_xor_si256(D1, A1); \
|
||||
D1 = rotr16(D1); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C1, D1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
|
||||
B1 = _mm256_xor_si256(B1, C1); \
|
||||
B1 = rotr63(B1); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
\
|
||||
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
|
||||
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
|
||||
B1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
B0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
\
|
||||
tmp1 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = tmp1; \
|
||||
\
|
||||
tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \
|
||||
tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \
|
||||
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
} while(0);
|
||||
|
||||
#define UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
\
|
||||
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
|
||||
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
|
||||
B0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
B1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
\
|
||||
tmp1 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = tmp1; \
|
||||
\
|
||||
tmp1 = _mm256_blend_epi32(D0, D1, 0x33); \
|
||||
tmp2 = _mm256_blend_epi32(D0, D1, 0xCC); \
|
||||
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define BLAKE2_ROUND_1(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do{ \
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
\
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do{ \
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
} while((void)0, 0);
|
||||
|
||||
#endif /* __AVX2__ */
|
||||
|
||||
#else /* __AVX512F__ */
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
#define ror64(x, n) _mm512_ror_epi64((x), (n))
|
||||
|
||||
static __m512i muladd(__m512i x, __m512i y)
|
||||
{
|
||||
__m512i z = _mm512_mul_epu32(x, y);
|
||||
return _mm512_add_epi64(_mm512_add_epi64(x, y), _mm512_add_epi64(z, z));
|
||||
}
|
||||
|
||||
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = muladd(A0, B0); \
|
||||
A1 = muladd(A1, B1); \
|
||||
\
|
||||
D0 = _mm512_xor_si512(D0, A0); \
|
||||
D1 = _mm512_xor_si512(D1, A1); \
|
||||
\
|
||||
D0 = ror64(D0, 32); \
|
||||
D1 = ror64(D1, 32); \
|
||||
\
|
||||
C0 = muladd(C0, D0); \
|
||||
C1 = muladd(C1, D1); \
|
||||
\
|
||||
B0 = _mm512_xor_si512(B0, C0); \
|
||||
B1 = _mm512_xor_si512(B1, C1); \
|
||||
\
|
||||
B0 = ror64(B0, 24); \
|
||||
B1 = ror64(B1, 24); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = muladd(A0, B0); \
|
||||
A1 = muladd(A1, B1); \
|
||||
\
|
||||
D0 = _mm512_xor_si512(D0, A0); \
|
||||
D1 = _mm512_xor_si512(D1, A1); \
|
||||
\
|
||||
D0 = ror64(D0, 16); \
|
||||
D1 = ror64(D1, 16); \
|
||||
\
|
||||
C0 = muladd(C0, D0); \
|
||||
C1 = muladd(C1, D1); \
|
||||
\
|
||||
B0 = _mm512_xor_si512(B0, C0); \
|
||||
B1 = _mm512_xor_si512(B1, C1); \
|
||||
\
|
||||
B0 = ror64(B0, 63); \
|
||||
B1 = ror64(B1, 63); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
\
|
||||
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
\
|
||||
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
\
|
||||
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
\
|
||||
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define SWAP_HALVES(A0, A1) \
|
||||
do { \
|
||||
__m512i t0, t1; \
|
||||
t0 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(1, 0, 1, 0)); \
|
||||
t1 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(3, 2, 3, 2)); \
|
||||
A0 = t0; \
|
||||
A1 = t1; \
|
||||
} while((void)0, 0)
|
||||
|
||||
#define SWAP_QUARTERS(A0, A1) \
|
||||
do { \
|
||||
SWAP_HALVES(A0, A1); \
|
||||
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
|
||||
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
|
||||
} while((void)0, 0)
|
||||
|
||||
#define UNSWAP_QUARTERS(A0, A1) \
|
||||
do { \
|
||||
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
|
||||
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
|
||||
SWAP_HALVES(A0, A1); \
|
||||
} while((void)0, 0)
|
||||
|
||||
#define BLAKE2_ROUND_1(A0, C0, B0, D0, A1, C1, B1, D1) \
|
||||
do { \
|
||||
SWAP_HALVES(A0, B0); \
|
||||
SWAP_HALVES(C0, D0); \
|
||||
SWAP_HALVES(A1, B1); \
|
||||
SWAP_HALVES(C1, D1); \
|
||||
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
SWAP_HALVES(A0, B0); \
|
||||
SWAP_HALVES(C0, D0); \
|
||||
SWAP_HALVES(A1, B1); \
|
||||
SWAP_HALVES(C1, D1); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
SWAP_QUARTERS(A0, A1); \
|
||||
SWAP_QUARTERS(B0, B1); \
|
||||
SWAP_QUARTERS(C0, C1); \
|
||||
SWAP_QUARTERS(D0, D1); \
|
||||
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
UNSWAP_QUARTERS(A0, A1); \
|
||||
UNSWAP_QUARTERS(B0, B1); \
|
||||
UNSWAP_QUARTERS(C0, C1); \
|
||||
UNSWAP_QUARTERS(D0, D1); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#endif /* __AVX512F__ */
|
||||
#endif /* BLAKE_ROUND_MKA_OPT_H */
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "blake2.h"
|
||||
#include "blake2-impl.h"
|
||||
|
||||
/*designed by the Lyra PHC team */
|
||||
/* designed by the Lyra PHC team */
|
||||
static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) {
|
||||
const uint64_t m = UINT64_C(0xFFFFFFFF);
|
||||
const uint64_t xy = (x & m) * (y & m);
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#endif
|
||||
#define VC_GE_2005(version) (version >= 1400)
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -396,11 +395,11 @@ int validate_inputs(const argon2_context *context) {
|
||||
return ARGON2_PWD_PTR_MISMATCH;
|
||||
}
|
||||
}
|
||||
|
||||
#if ARGON2_MIN_PWD_LENGTH > 0 /* cryptsetup: fix gcc warning */
|
||||
if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) {
|
||||
return ARGON2_PWD_TOO_SHORT;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {
|
||||
return ARGON2_PWD_TOO_LONG;
|
||||
}
|
||||
@@ -426,9 +425,11 @@ int validate_inputs(const argon2_context *context) {
|
||||
return ARGON2_SECRET_PTR_MISMATCH;
|
||||
}
|
||||
} else {
|
||||
#if ARGON2_MIN_SECRET > 0 /* cryptsetup: fix gcc warning */
|
||||
if (ARGON2_MIN_SECRET > context->secretlen) {
|
||||
return ARGON2_SECRET_TOO_SHORT;
|
||||
}
|
||||
#endif
|
||||
if (ARGON2_MAX_SECRET < context->secretlen) {
|
||||
return ARGON2_SECRET_TOO_LONG;
|
||||
}
|
||||
@@ -440,9 +441,11 @@ int validate_inputs(const argon2_context *context) {
|
||||
return ARGON2_AD_PTR_MISMATCH;
|
||||
}
|
||||
} else {
|
||||
#if ARGON2_MIN_AD_LENGTH > 0 /* cryptsetup: fix gcc warning */
|
||||
if (ARGON2_MIN_AD_LENGTH > context->adlen) {
|
||||
return ARGON2_AD_TOO_SHORT;
|
||||
}
|
||||
#endif
|
||||
if (ARGON2_MAX_AD_LENGTH < context->adlen) {
|
||||
return ARGON2_AD_TOO_LONG;
|
||||
}
|
||||
@@ -452,11 +455,11 @@ int validate_inputs(const argon2_context *context) {
|
||||
if (ARGON2_MIN_MEMORY > context->m_cost) {
|
||||
return ARGON2_MEMORY_TOO_LITTLE;
|
||||
}
|
||||
|
||||
#if 0 /* UINT32_MAX, cryptsetup: fix gcc warning */
|
||||
if (ARGON2_MAX_MEMORY < context->m_cost) {
|
||||
return ARGON2_MEMORY_TOO_MUCH;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (context->m_cost < 8 * context->lanes) {
|
||||
return ARGON2_MEMORY_TOO_LITTLE;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ enum argon2_core_constants {
|
||||
ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,
|
||||
ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,
|
||||
ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,
|
||||
ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,
|
||||
|
||||
/* Number of pseudo-random values generated by one call to Blake in Argon2i
|
||||
to
|
||||
|
||||
283
lib/crypto_backend/argon2/opt.c
Normal file
283
lib/crypto_backend/argon2/opt.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
||||
* these licenses can be found at:
|
||||
*
|
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* You should have received a copy of both of these licenses along with this
|
||||
* software. If not, they may be obtained at the above URLs.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "argon2.h"
|
||||
#include "core.h"
|
||||
|
||||
#include "blake2/blake2.h"
|
||||
#include "blake2/blamka-round-opt.h"
|
||||
|
||||
/*
|
||||
* Function fills a new memory block and optionally XORs the old block over the new one.
|
||||
* Memory must be initialized.
|
||||
* @param state Pointer to the just produced block. Content will be updated(!)
|
||||
* @param ref_block Pointer to the reference block
|
||||
* @param next_block Pointer to the block to be XORed over. May coincide with @ref_block
|
||||
* @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
|
||||
* @pre all block pointers must be valid
|
||||
*/
|
||||
#if defined(__AVX512F__)
|
||||
static void fill_block(__m512i *state, const block *ref_block,
|
||||
block *next_block, int with_xor) {
|
||||
__m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
unsigned int i;
|
||||
|
||||
if (with_xor) {
|
||||
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm512_xor_si512(
|
||||
state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
|
||||
block_XY[i] = _mm512_xor_si512(
|
||||
state[i], _mm512_loadu_si512((const __m512i *)next_block->v + i));
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
|
||||
block_XY[i] = state[i] = _mm512_xor_si512(
|
||||
state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
BLAKE2_ROUND_1(
|
||||
state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
|
||||
state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
BLAKE2_ROUND_2(
|
||||
state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i],
|
||||
state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm512_xor_si512(state[i], block_XY[i]);
|
||||
_mm512_storeu_si512((__m512i *)next_block->v + i, state[i]);
|
||||
}
|
||||
}
|
||||
#elif defined(__AVX2__)
|
||||
static void fill_block(__m256i *state, const block *ref_block,
|
||||
block *next_block, int with_xor) {
|
||||
__m256i block_XY[ARGON2_HWORDS_IN_BLOCK];
|
||||
unsigned int i;
|
||||
|
||||
if (with_xor) {
|
||||
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm256_xor_si256(
|
||||
state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
|
||||
block_XY[i] = _mm256_xor_si256(
|
||||
state[i], _mm256_loadu_si256((const __m256i *)next_block->v + i));
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
|
||||
block_XY[i] = state[i] = _mm256_xor_si256(
|
||||
state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],
|
||||
state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i],
|
||||
state[16 + i], state[20 + i], state[24 + i], state[28 + i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm256_xor_si256(state[i], block_XY[i]);
|
||||
_mm256_storeu_si256((__m256i *)next_block->v + i, state[i]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void fill_block(__m128i *state, const block *ref_block,
|
||||
block *next_block, int with_xor) {
|
||||
__m128i block_XY[ARGON2_OWORDS_IN_BLOCK];
|
||||
unsigned int i;
|
||||
|
||||
if (with_xor) {
|
||||
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm_xor_si128(
|
||||
state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));
|
||||
block_XY[i] = _mm_xor_si128(
|
||||
state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
|
||||
block_XY[i] = state[i] = _mm_xor_si128(
|
||||
state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2],
|
||||
state[8 * i + 3], state[8 * i + 4], state[8 * i + 5],
|
||||
state[8 * i + 6], state[8 * i + 7]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i],
|
||||
state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i],
|
||||
state[8 * 6 + i], state[8 * 7 + i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm_xor_si128(state[i], block_XY[i]);
|
||||
_mm_storeu_si128((__m128i *)next_block->v + i, state[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void next_addresses(block *address_block, block *input_block) {
|
||||
/*Temporary zero-initialized blocks*/
|
||||
#if defined(__AVX512F__)
|
||||
__m512i zero_block[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
__m512i zero2_block[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
#elif defined(__AVX2__)
|
||||
__m256i zero_block[ARGON2_HWORDS_IN_BLOCK];
|
||||
__m256i zero2_block[ARGON2_HWORDS_IN_BLOCK];
|
||||
#else
|
||||
__m128i zero_block[ARGON2_OWORDS_IN_BLOCK];
|
||||
__m128i zero2_block[ARGON2_OWORDS_IN_BLOCK];
|
||||
#endif
|
||||
|
||||
memset(zero_block, 0, sizeof(zero_block));
|
||||
memset(zero2_block, 0, sizeof(zero2_block));
|
||||
|
||||
/*Increasing index counter*/
|
||||
input_block->v[6]++;
|
||||
|
||||
/*First iteration of G*/
|
||||
fill_block(zero_block, input_block, address_block, 0);
|
||||
|
||||
/*Second iteration of G*/
|
||||
fill_block(zero2_block, address_block, address_block, 0);
|
||||
}
|
||||
|
||||
void fill_segment(const argon2_instance_t *instance,
|
||||
argon2_position_t position) {
|
||||
block *ref_block = NULL, *curr_block = NULL;
|
||||
block address_block, input_block;
|
||||
uint64_t pseudo_rand, ref_index, ref_lane;
|
||||
uint32_t prev_offset, curr_offset;
|
||||
uint32_t starting_index, i;
|
||||
#if defined(__AVX512F__)
|
||||
__m512i state[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
#elif defined(__AVX2__)
|
||||
__m256i state[ARGON2_HWORDS_IN_BLOCK];
|
||||
#else
|
||||
__m128i state[ARGON2_OWORDS_IN_BLOCK];
|
||||
#endif
|
||||
int data_independent_addressing;
|
||||
|
||||
if (instance == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_independent_addressing =
|
||||
(instance->type == Argon2_i) ||
|
||||
(instance->type == Argon2_id && (position.pass == 0) &&
|
||||
(position.slice < ARGON2_SYNC_POINTS / 2));
|
||||
|
||||
if (data_independent_addressing) {
|
||||
init_block_value(&input_block, 0);
|
||||
|
||||
input_block.v[0] = position.pass;
|
||||
input_block.v[1] = position.lane;
|
||||
input_block.v[2] = position.slice;
|
||||
input_block.v[3] = instance->memory_blocks;
|
||||
input_block.v[4] = instance->passes;
|
||||
input_block.v[5] = instance->type;
|
||||
}
|
||||
|
||||
starting_index = 0;
|
||||
|
||||
if ((0 == position.pass) && (0 == position.slice)) {
|
||||
starting_index = 2; /* we have already generated the first two blocks */
|
||||
|
||||
/* Don't forget to generate the first block of addresses: */
|
||||
if (data_independent_addressing) {
|
||||
next_addresses(&address_block, &input_block);
|
||||
}
|
||||
}
|
||||
|
||||
/* Offset of the current block */
|
||||
curr_offset = position.lane * instance->lane_length +
|
||||
position.slice * instance->segment_length + starting_index;
|
||||
|
||||
if (0 == curr_offset % instance->lane_length) {
|
||||
/* Last block in this lane */
|
||||
prev_offset = curr_offset + instance->lane_length - 1;
|
||||
} else {
|
||||
/* Previous block */
|
||||
prev_offset = curr_offset - 1;
|
||||
}
|
||||
|
||||
memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE);
|
||||
|
||||
for (i = starting_index; i < instance->segment_length;
|
||||
++i, ++curr_offset, ++prev_offset) {
|
||||
/*1.1 Rotating prev_offset if needed */
|
||||
if (curr_offset % instance->lane_length == 1) {
|
||||
prev_offset = curr_offset - 1;
|
||||
}
|
||||
|
||||
/* 1.2 Computing the index of the reference block */
|
||||
/* 1.2.1 Taking pseudo-random value from the previous block */
|
||||
if (data_independent_addressing) {
|
||||
if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
|
||||
next_addresses(&address_block, &input_block);
|
||||
}
|
||||
pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
|
||||
} else {
|
||||
pseudo_rand = instance->memory[prev_offset].v[0];
|
||||
}
|
||||
|
||||
/* 1.2.2 Computing the lane of the reference block */
|
||||
ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
|
||||
|
||||
if ((position.pass == 0) && (position.slice == 0)) {
|
||||
/* Can not reference other lanes yet */
|
||||
ref_lane = position.lane;
|
||||
}
|
||||
|
||||
/* 1.2.3 Computing the number of possible reference block within the
|
||||
* lane.
|
||||
*/
|
||||
position.index = i;
|
||||
ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
|
||||
ref_lane == position.lane);
|
||||
|
||||
/* 2 Creating a new block */
|
||||
ref_block =
|
||||
instance->memory + instance->lane_length * ref_lane + ref_index;
|
||||
curr_block = instance->memory + curr_offset;
|
||||
if (ARGON2_VERSION_10 == instance->version) {
|
||||
/* version 1.2.1 and earlier: overwrite, not XOR */
|
||||
fill_block(state, ref_block, curr_block, 0);
|
||||
} else {
|
||||
if(0 == position.pass) {
|
||||
fill_block(state, ref_block, curr_block, 0);
|
||||
} else {
|
||||
fill_block(state, ref_block, curr_block, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ typedef pthread_t argon2_thread_handle_t;
|
||||
* @param func A function pointer for the thread's entry point. Must not be
|
||||
* NULL.
|
||||
* @param args Pointer that is passed as an argument to @func. May be NULL.
|
||||
* @return 0 if @handle and @func are valid pointers and a thread is successfuly
|
||||
* @return 0 if @handle and @func are valid pointers and a thread is successfully
|
||||
* created.
|
||||
*/
|
||||
int argon2_thread_create(argon2_thread_handle_t *handle,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Argon2 PBKDF2 library wrapper
|
||||
*
|
||||
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2017, Milan Broz
|
||||
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
78
lib/crypto_backend/cipher_generic.c
Normal file
78
lib/crypto_backend/cipher_generic.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Linux kernel cipher generic utilities
|
||||
*
|
||||
* Copyright (C) 2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include "crypto_backend.h"
|
||||
|
||||
struct cipher_alg {
|
||||
const char *name;
|
||||
int blocksize;
|
||||
bool wrapped_key;
|
||||
};
|
||||
|
||||
/* FIXME: Getting block size should be dynamic from cipher backend. */
|
||||
static const struct cipher_alg cipher_algs[] = {
|
||||
{ "cipher_null", 16, false },
|
||||
{ "aes", 16, false },
|
||||
{ "serpent", 16, false },
|
||||
{ "twofish", 16, false },
|
||||
{ "anubis", 16, false },
|
||||
{ "blowfish", 8, false },
|
||||
{ "camellia", 16, false },
|
||||
{ "cast5", 8, false },
|
||||
{ "cast6", 16, false },
|
||||
{ "des", 8, false },
|
||||
{ "des3_ede", 8, false },
|
||||
{ "khazad", 8, false },
|
||||
{ "seed", 16, false },
|
||||
{ "tea", 8, false },
|
||||
{ "xtea", 8, false },
|
||||
{ "paes", 16, true }, /* protected AES, s390 wrapped key scheme */
|
||||
{ NULL, 0, false }
|
||||
};
|
||||
|
||||
static const struct cipher_alg *_get_alg(const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (name && cipher_algs[i].name) {
|
||||
if (!strcasecmp(name, cipher_algs[i].name))
|
||||
return &cipher_algs[i];
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int crypt_cipher_blocksize(const char *name)
|
||||
{
|
||||
const struct cipher_alg *ca = _get_alg(name);
|
||||
|
||||
return ca ? ca->blocksize : -EINVAL;
|
||||
}
|
||||
|
||||
int crypt_cipher_wrapped_key(const char *name)
|
||||
{
|
||||
const struct cipher_alg *ca = _get_alg(name);
|
||||
|
||||
return ca ? (int)ca->wrapped_key : 0;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -22,6 +22,7 @@
|
||||
#define _CRYPTO_BACKEND_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
struct crypt_device;
|
||||
@@ -43,20 +44,27 @@ int crypt_hash_size(const char *name);
|
||||
int crypt_hash_init(struct crypt_hash **ctx, const char *name);
|
||||
int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length);
|
||||
int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length);
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx);
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx);
|
||||
|
||||
/* HMAC */
|
||||
int crypt_hmac_size(const char *name);
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length);
|
||||
const void *key, size_t key_length);
|
||||
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length);
|
||||
int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length);
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx);
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx);
|
||||
|
||||
/* RNG (if fips paramater set, must provide FIPS compliance) */
|
||||
/* RNG (if fips parameter set, must provide FIPS compliance) */
|
||||
enum { CRYPT_RND_NORMAL = 0, CRYPT_RND_KEY = 1, CRYPT_RND_SALT = 2 };
|
||||
int crypt_backend_rng(char *buffer, size_t length, int quality, int fips);
|
||||
|
||||
struct crypt_pbkdf_limits {
|
||||
uint32_t min_iterations, max_iterations;
|
||||
uint32_t min_memory, max_memory;
|
||||
uint32_t min_parallel, max_parallel;
|
||||
};
|
||||
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *l);
|
||||
|
||||
/* PBKDF*/
|
||||
int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
const char *password, size_t password_length,
|
||||
@@ -92,9 +100,10 @@ uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len);
|
||||
|
||||
/* ciphers */
|
||||
int crypt_cipher_blocksize(const char *name);
|
||||
int crypt_cipher_wrapped_key(const char *name);
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *buffer, size_t length);
|
||||
int crypt_cipher_destroy(struct crypt_cipher *ctx);
|
||||
const char *mode, const void *key, size_t key_length);
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx);
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length);
|
||||
@@ -105,8 +114,8 @@ int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
/* storage encryption wrappers */
|
||||
int crypt_storage_init(struct crypt_storage **ctx, uint64_t sector_start,
|
||||
const char *cipher, const char *cipher_mode,
|
||||
char *key, size_t key_length);
|
||||
int crypt_storage_destroy(struct crypt_storage *ctx);
|
||||
const void *key, size_t key_length);
|
||||
void crypt_storage_destroy(struct crypt_storage *ctx);
|
||||
int crypt_storage_decrypt(struct crypt_storage *ctx, uint64_t sector,
|
||||
size_t count, char *buffer);
|
||||
int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t sector,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Linux kernel userspace API crypto backend implementation (skcipher)
|
||||
*
|
||||
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -44,59 +44,15 @@ struct crypt_cipher {
|
||||
int opfd;
|
||||
};
|
||||
|
||||
struct cipher_alg {
|
||||
const char *name;
|
||||
int blocksize;
|
||||
};
|
||||
|
||||
/* FIXME: Getting block size should be dynamic from cipher backend. */
|
||||
static struct cipher_alg cipher_algs[] = {
|
||||
{ "cipher_null", 16 },
|
||||
{ "aes", 16 },
|
||||
{ "serpent", 16 },
|
||||
{ "twofish", 16 },
|
||||
{ "anubis", 16 },
|
||||
{ "blowfish", 8 },
|
||||
{ "camellia", 16 },
|
||||
{ "cast5", 8 },
|
||||
{ "cast6", 16 },
|
||||
{ "des", 8 },
|
||||
{ "des3_ede", 8 },
|
||||
{ "khazad", 8 },
|
||||
{ "seed", 16 },
|
||||
{ "tea", 8 },
|
||||
{ "xtea", 8 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static struct cipher_alg *_get_alg(const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (name && cipher_algs[i].name) {
|
||||
if (!strcasecmp(name, cipher_algs[i].name))
|
||||
return &cipher_algs[i];
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int crypt_cipher_blocksize(const char *name)
|
||||
{
|
||||
struct cipher_alg *ca = _get_alg(name);
|
||||
|
||||
return ca ? ca->blocksize : -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ciphers
|
||||
*
|
||||
* ENOENT - algorithm not available
|
||||
* ENOTSUP - AF_ALG family not available
|
||||
* (but cannot check specificaly for skcipher API)
|
||||
* (but cannot check specifically for skcipher API)
|
||||
*/
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *buffer, size_t length)
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
struct sockaddr_alg sa = {
|
||||
@@ -124,9 +80,9 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
}
|
||||
|
||||
if (!strcmp(name, "cipher_null"))
|
||||
length = 0;
|
||||
key_length = 0;
|
||||
|
||||
if (setsockopt(h->tfmfd, SOL_ALG, ALG_SET_KEY, buffer, length) < 0) {
|
||||
if (setsockopt(h->tfmfd, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
|
||||
crypt_cipher_destroy(h);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -225,7 +181,7 @@ int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
iv, iv_length, ALG_OP_DECRYPT);
|
||||
}
|
||||
|
||||
int crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
if (ctx->tfmfd >= 0)
|
||||
close(ctx->tfmfd);
|
||||
@@ -233,25 +189,18 @@ int crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
close(ctx->opfd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* ENABLE_AF_ALG */
|
||||
|
||||
int crypt_cipher_blocksize(const char *name)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *buffer, size_t length)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* GCRYPT crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -225,12 +225,11 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
gcry_md_close(ctx->hd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HMAC */
|
||||
@@ -240,7 +239,7 @@ int crypt_hmac_size(const char *name)
|
||||
}
|
||||
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
unsigned int flags = GCRY_MD_FLAG_HMAC;
|
||||
@@ -262,7 +261,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (gcry_md_setkey(h->hd, buffer, length)) {
|
||||
if (gcry_md_setkey(h->hd, key, key_length)) {
|
||||
gcry_md_close(h->hd);
|
||||
free(h);
|
||||
return -EINVAL;
|
||||
@@ -301,12 +300,11 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
gcry_md_close(ctx->hd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RNG */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Linux kernel userspace API crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -217,7 +217,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
if (ctx->tfmfd >= 0)
|
||||
close(ctx->tfmfd);
|
||||
@@ -225,7 +225,6 @@ int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
close(ctx->opfd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HMAC */
|
||||
@@ -235,7 +234,7 @@ int crypt_hmac_size(const char *name)
|
||||
}
|
||||
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
struct hash_alg *ha;
|
||||
@@ -258,7 +257,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
snprintf((char *)sa.salg_name, sizeof(sa.salg_name),
|
||||
"hmac(%s)", ha->kernel_name);
|
||||
|
||||
if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd, buffer, length) < 0) {
|
||||
if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd, key, key_length) < 0) {
|
||||
free(h);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -292,7 +291,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
if (ctx->tfmfd >= 0)
|
||||
close(ctx->tfmfd);
|
||||
@@ -300,7 +299,6 @@ int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
close(ctx->opfd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RNG - N/A */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Nettle crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2017, Milan Broz
|
||||
* Copyright (C) 2011-2018 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -202,11 +202,10 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HMAC */
|
||||
@@ -216,7 +215,7 @@ int crypt_hmac_size(const char *name)
|
||||
}
|
||||
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
|
||||
@@ -230,12 +229,12 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
if (!h->hash)
|
||||
goto bad;
|
||||
|
||||
h->key = malloc(length);
|
||||
h->key = malloc(key_length);
|
||||
if (!h->key)
|
||||
goto bad;
|
||||
|
||||
memcpy(h->key, buffer, length);
|
||||
h->key_length = length;
|
||||
memcpy(h->key, key, key_length);
|
||||
h->key_length = key_length;
|
||||
|
||||
h->hash->init(&h->nettle_ctx);
|
||||
h->hash->hmac_set_key(&h->nettle_ctx, h->key_length, h->key);
|
||||
@@ -268,13 +267,12 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
memset(ctx->key, 0, ctx->key_length);
|
||||
free(ctx->key);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RNG - N/A */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* NSS crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -180,12 +180,11 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
PK11_DestroyContext(ctx->md, PR_TRUE);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HMAC */
|
||||
@@ -195,15 +194,15 @@ int crypt_hmac_size(const char *name)
|
||||
}
|
||||
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
SECItem keyItem;
|
||||
SECItem noParams;
|
||||
|
||||
keyItem.type = siBuffer;
|
||||
keyItem.data = CONST_CAST(unsigned char *)buffer;
|
||||
keyItem.len = (int)length;
|
||||
keyItem.data = CONST_CAST(unsigned char *)key;
|
||||
keyItem.len = (int)key_length;
|
||||
|
||||
noParams.type = siBuffer;
|
||||
noParams.data = 0;
|
||||
@@ -282,7 +281,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
if (ctx->key)
|
||||
PK11_FreeSymKey(ctx->key);
|
||||
@@ -292,7 +291,6 @@ int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
PK11_DestroyContext(ctx->md, PR_TRUE);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RNG */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* OPENSSL crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2017, Milan Broz
|
||||
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -50,9 +50,11 @@ struct crypt_hmac {
|
||||
};
|
||||
|
||||
/*
|
||||
* Compatible wrappers for OpenSSL < 1.1.0
|
||||
* Compatible wrappers for OpenSSL < 1.1.0 and LibreSSL < 2.7.0
|
||||
*/
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||
|
||||
static void openssl_backend_init(void)
|
||||
{
|
||||
OpenSSL_add_all_algorithms();
|
||||
@@ -213,12 +215,11 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
EVP_MD_CTX_free(ctx->md);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HMAC */
|
||||
@@ -228,7 +229,7 @@ int crypt_hmac_size(const char *name)
|
||||
}
|
||||
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
|
||||
@@ -249,7 +250,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
HMAC_Init_ex(h->md, buffer, length, h->hash_id, NULL);
|
||||
HMAC_Init_ex(h->md, key, key_length, h->hash_id, NULL);
|
||||
|
||||
h->hash_len = EVP_MD_size(h->hash_id);
|
||||
*ctx = h;
|
||||
@@ -288,12 +289,11 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
HMAC_CTX_free(ctx->md);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RNG */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Generic wrapper for storage encryption modes and Initial Vectors
|
||||
* (reimplementation of some functions from Linux dm-crypt kernel)
|
||||
*
|
||||
* Copyright (C) 2014-2017, Milan Broz
|
||||
* Copyright (C) 2014-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -56,7 +56,7 @@ static int int_log2(unsigned int x)
|
||||
|
||||
static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
|
||||
const char *cipher_name, const char *mode_name,
|
||||
const char *iv_name, char *key, size_t key_length)
|
||||
const char *iv_name, const void *key, size_t key_length)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
@@ -64,12 +64,15 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
|
||||
if (ctx->iv_size < 8)
|
||||
return -ENOENT;
|
||||
|
||||
if (!iv_name ||
|
||||
!strcmp(cipher_name, "cipher_null") ||
|
||||
if (!strcmp(cipher_name, "cipher_null") ||
|
||||
!strcmp(mode_name, "ecb")) {
|
||||
if (iv_name)
|
||||
return -EINVAL;
|
||||
ctx->type = IV_NONE;
|
||||
ctx->iv_size = 0;
|
||||
return 0;
|
||||
} else if (!iv_name) {
|
||||
return -EINVAL;
|
||||
} else if (!strcasecmp(iv_name, "null")) {
|
||||
ctx->type = IV_NULL;
|
||||
} else if (!strcasecmp(iv_name, "plain64")) {
|
||||
@@ -175,7 +178,7 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
|
||||
static void crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
|
||||
{
|
||||
if (ctx->type == IV_ESSIV)
|
||||
crypt_cipher_destroy(ctx->essiv_cipher);
|
||||
@@ -186,7 +189,6 @@ static int crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
|
||||
}
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Block encryption storage wrappers */
|
||||
@@ -195,7 +197,7 @@ int crypt_storage_init(struct crypt_storage **ctx,
|
||||
uint64_t sector_start,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
char *key, size_t key_length)
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_storage *s;
|
||||
char mode_name[64];
|
||||
@@ -282,10 +284,10 @@ int crypt_storage_encrypt(struct crypt_storage *ctx,
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_storage_destroy(struct crypt_storage *ctx)
|
||||
void crypt_storage_destroy(struct crypt_storage *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
crypt_sector_iv_destroy(&ctx->cipher_iv);
|
||||
|
||||
@@ -294,6 +296,4 @@ int crypt_storage_destroy(struct crypt_storage *ctx)
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* Copyright (C) 2004 Free Software Foundation
|
||||
*
|
||||
* cryptsetup related changes
|
||||
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* PBKDF performance check
|
||||
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2016-2017, Ondrej Mosnacek
|
||||
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2018, Milan Broz
|
||||
* Copyright (C) 2016-2018, Ondrej Mosnacek
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -34,6 +34,33 @@
|
||||
#define BENCH_SAMPLES_FAST 3
|
||||
#define BENCH_SAMPLES_SLOW 1
|
||||
|
||||
/* These PBKDF2 limits must be never violated */
|
||||
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *limits)
|
||||
{
|
||||
if (!kdf || !limits)
|
||||
return -EINVAL;
|
||||
|
||||
if (!strcmp(kdf, "pbkdf2")) {
|
||||
limits->min_iterations = 1000; /* recommendation in NIST SP 800-132 */
|
||||
limits->max_iterations = UINT32_MAX;
|
||||
limits->min_memory = 0; /* N/A */
|
||||
limits->max_memory = 0; /* N/A */
|
||||
limits->min_parallel = 0; /* N/A */
|
||||
limits->max_parallel = 0; /* N/A */
|
||||
return 0;
|
||||
} else if (!strncmp(kdf, "argon2", 6)) {
|
||||
limits->min_iterations = 4;
|
||||
limits->max_iterations = UINT32_MAX;
|
||||
limits->min_memory = 32;
|
||||
limits->max_memory = 4*1024*1024; /* 4GiB */
|
||||
limits->min_parallel = 1;
|
||||
limits->max_parallel = 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static long time_ms(struct rusage *start, struct rusage *end)
|
||||
{
|
||||
int count_kernel_time = 0;
|
||||
@@ -362,8 +389,6 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
#define ARGON2_MIN_T_COST 4
|
||||
|
||||
int crypt_pbkdf_perf(const char *kdf, const char *hash,
|
||||
const char *password, size_t password_size,
|
||||
const char *salt, size_t salt_size,
|
||||
@@ -372,11 +397,16 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
|
||||
uint32_t *iterations_out, uint32_t *memory_out,
|
||||
int (*progress)(uint32_t time_ms, void *usrptr), void *usrptr)
|
||||
{
|
||||
struct crypt_pbkdf_limits pbkdf_limits;
|
||||
int r = -EINVAL;
|
||||
|
||||
if (!kdf || !iterations_out || !memory_out)
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_pbkdf_get_limits(kdf, &pbkdf_limits);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*memory_out = 0;
|
||||
*iterations_out = 0;
|
||||
|
||||
@@ -388,7 +418,7 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
|
||||
else if (!strncmp(kdf, "argon2", 6))
|
||||
r = crypt_argon2_check(kdf, password, password_size,
|
||||
salt, salt_size, volume_key_size,
|
||||
ARGON2_MIN_T_COST, max_memory_kb,
|
||||
pbkdf_limits.min_iterations, max_memory_kb,
|
||||
parallel_threads, time_ms, iterations_out,
|
||||
memory_out, progress, usrptr);
|
||||
return r;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Integrity volume handling
|
||||
*
|
||||
* Copyright (C) 2016-2017, Milan Broz
|
||||
* Copyright (C) 2016-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -42,7 +42,7 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
|
||||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
|
||||
sb->version != SB_VERSION) {
|
||||
(sb->version != SB_VERSION_1 && sb->version != SB_VERSION_2)) {
|
||||
log_std(cd, "No integrity superblock detected on %s.\n",
|
||||
device_path(device));
|
||||
r = -EINVAL;
|
||||
@@ -50,6 +50,8 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
|
||||
sb->integrity_tag_size = le16toh(sb->integrity_tag_size);
|
||||
sb->journal_sections = le32toh(sb->journal_sections);
|
||||
sb->provided_data_sectors = le64toh(sb->provided_data_sectors);
|
||||
sb->recalc_sector = le64toh(sb->recalc_sector);
|
||||
sb->flags = le32toh(sb->flags);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
@@ -82,11 +84,17 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
|
||||
return r;
|
||||
|
||||
log_std(cd, "Info for integrity device %s.\n", device_path(device));
|
||||
log_std(cd, "superblock_version %d\n", (unsigned)sb.version);
|
||||
log_std(cd, "log2_interleave_sectors %d\n", sb.log2_interleave_sectors);
|
||||
log_std(cd, "integrity_tag_size %u\n", sb.integrity_tag_size);
|
||||
log_std(cd, "journal_sections %u\n", sb.journal_sections);
|
||||
log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
|
||||
log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
|
||||
if (sb.version == SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
|
||||
log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
|
||||
log_std(cd, "flags %s%s\n",
|
||||
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
|
||||
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -106,16 +114,16 @@ int INTEGRITY_data_sectors(struct crypt_device *cd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int INTEGRITY_key_size(struct crypt_device *cd)
|
||||
int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity)
|
||||
{
|
||||
const char *integrity = crypt_get_integrity(cd);
|
||||
|
||||
if (!integrity)
|
||||
return 0;
|
||||
|
||||
//FIXME: use crypto backend hash size
|
||||
if (!strcmp(integrity, "aead"))
|
||||
return 0;
|
||||
else if (!strcmp(integrity, "hmac(sha1)"))
|
||||
return 20;
|
||||
else if (!strcmp(integrity, "hmac(sha256)"))
|
||||
return 32;
|
||||
else if (!strcmp(integrity, "hmac(sha512)"))
|
||||
@@ -130,6 +138,7 @@ int INTEGRITY_key_size(struct crypt_device *cd)
|
||||
|
||||
int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
const char *integrity,
|
||||
const char *cipher,
|
||||
const char *cipher_mode)
|
||||
{
|
||||
int iv_tag_size = 0, auth_tag_size = 0;
|
||||
@@ -144,6 +153,8 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
iv_tag_size = 8;
|
||||
else if (!strcmp(cipher_mode, "ctr-random"))
|
||||
iv_tag_size = 16;
|
||||
else if (!strcmp(cipher, "aegis256") && !strcmp(cipher_mode, "random"))
|
||||
iv_tag_size = 32;
|
||||
else if (!strcmp(cipher_mode, "random"))
|
||||
iv_tag_size = 16;
|
||||
|
||||
@@ -154,6 +165,8 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
auth_tag_size = 16; //FIXME gcm- mode only
|
||||
else if (!strcmp(integrity, "cmac(aes)"))
|
||||
auth_tag_size = 16;
|
||||
else if (!strcmp(integrity, "hmac(sha1)"))
|
||||
auth_tag_size = 20;
|
||||
else if (!strcmp(integrity, "hmac(sha256)"))
|
||||
auth_tag_size = 32;
|
||||
else if (!strcmp(integrity, "hmac(sha512)"))
|
||||
@@ -217,7 +230,7 @@ int INTEGRITY_activate(struct crypt_device *cd,
|
||||
|
||||
r = dm_create_device(cd, name, "INTEGRITY", &dmdi, 0);
|
||||
if (r < 0 && (dm_flags(DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
|
||||
log_err(cd, _("Kernel doesn't support dm-integrity mapping.\n"));
|
||||
log_err(cd, _("Kernel doesn't support dm-integrity mapping."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -268,13 +281,19 @@ int INTEGRITY_format(struct crypt_device *cd,
|
||||
|
||||
r = device_block_adjust(cd, dmdi.data_device, DEV_EXCL, dmdi.u.integrity.offset, NULL, NULL);
|
||||
if (r < 0 && (dm_flags(DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
|
||||
log_err(cd, _("Kernel doesn't support dm-integrity mapping.\n"));
|
||||
log_err(cd, _("Kernel doesn't support dm-integrity mapping."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* There is no data area, we can actually use fake zeroed key */
|
||||
if (params && params->integrity_key_size)
|
||||
dmdi.u.integrity.vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
|
||||
|
||||
r = dm_create_device(cd, tmp_name, "INTEGRITY", &dmdi, 0);
|
||||
|
||||
crypt_free_volume_key(dmdi.u.integrity.vk);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Integrity header defitinion
|
||||
*
|
||||
* Copyright (C) 2016-2017, Milan Broz
|
||||
* Copyright (C) 2016-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -30,7 +30,11 @@ struct volume_key;
|
||||
|
||||
/* dm-integrity helper */
|
||||
#define SB_MAGIC "integrt"
|
||||
#define SB_VERSION 1
|
||||
#define SB_VERSION_1 1
|
||||
#define SB_VERSION_2 2
|
||||
|
||||
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
|
||||
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
|
||||
|
||||
struct superblock {
|
||||
uint8_t magic[8];
|
||||
@@ -41,6 +45,8 @@ struct superblock {
|
||||
uint64_t provided_data_sectors;
|
||||
uint32_t flags;
|
||||
uint8_t log2_sectors_per_block;
|
||||
uint8_t pad[3];
|
||||
uint64_t recalc_sector; /* V2 only */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
int INTEGRITY_read_sb(struct crypt_device *cd, struct crypt_params_integrity *params);
|
||||
@@ -50,9 +56,11 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
|
||||
int INTEGRITY_data_sectors(struct crypt_device *cd,
|
||||
struct device *device, uint64_t offset,
|
||||
uint64_t *data_sectors);
|
||||
int INTEGRITY_key_size(struct crypt_device *cd);
|
||||
int INTEGRITY_key_size(struct crypt_device *cd,
|
||||
const char *integrity);
|
||||
int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
const char *integrity,
|
||||
const char *cipher,
|
||||
const char *cipher_mode);
|
||||
|
||||
int INTEGRITY_format(struct crypt_device *cd,
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -32,11 +32,13 @@
|
||||
|
||||
#include "nls.h"
|
||||
#include "bitops.h"
|
||||
#include "utils_blkid.h"
|
||||
#include "utils_crypt.h"
|
||||
#include "utils_loop.h"
|
||||
#include "utils_dm.h"
|
||||
#include "utils_fips.h"
|
||||
#include "utils_keyring.h"
|
||||
#include "utils_io.h"
|
||||
#include "crypto_backend.h"
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
@@ -49,15 +51,13 @@
|
||||
#define MAX_SECTOR_SIZE 4096 /* min page size among all platforms */
|
||||
#define DEFAULT_DISK_ALIGNMENT 1048576 /* 1MiB */
|
||||
#define DEFAULT_MEM_ALIGNMENT 4096
|
||||
#define MAX_ERROR_LENGTH 512
|
||||
|
||||
#define MAX_PBKDF_THREADS 4
|
||||
#define MAX_PBKDF_MEMORY 1024*1024 /* 1GiB */
|
||||
#define MIN_PBKDF2_ITERATIONS 1000 /* recommendation in NIST SP 800-132 */
|
||||
#define LOG_MAX_LEN 4096
|
||||
|
||||
#define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
|
||||
|
||||
#define CRYPT_DEFAULT_SEGMENT 0
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
struct crypt_device;
|
||||
|
||||
@@ -70,8 +70,7 @@ struct volume_key {
|
||||
struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key);
|
||||
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength);
|
||||
void crypt_free_volume_key(struct volume_key *vk);
|
||||
void crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
|
||||
const char *crypt_volume_key_get_description(const struct volume_key *key);
|
||||
int crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
|
||||
|
||||
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd);
|
||||
int init_pbkdf_type(struct crypt_device *cd,
|
||||
@@ -139,21 +138,13 @@ uint64_t crypt_dev_partition_offset(const char *dev_path);
|
||||
int lookup_by_disk_id(const char *dm_uuid);
|
||||
int lookup_by_sysfs_uuid_field(const char *dm_uuid, size_t max_len);
|
||||
|
||||
ssize_t write_buffer(int fd, const void *buf, size_t count);
|
||||
ssize_t read_buffer(int fd, void *buf, size_t count);
|
||||
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment, void *orig_buf, size_t count);
|
||||
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count);
|
||||
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count, off_t offset);
|
||||
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count, off_t offset);
|
||||
|
||||
size_t crypt_getpagesize(void);
|
||||
unsigned crypt_cpusonline(void);
|
||||
uint64_t crypt_getphysmemory_kb(void);
|
||||
|
||||
int init_crypto(struct crypt_device *ctx);
|
||||
|
||||
const char *uint64_to_str(char *buffer, size_t size, const uint64_t *val);
|
||||
|
||||
void logger(struct crypt_device *cd, int class, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
|
||||
void logger(struct crypt_device *cd, int level, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
|
||||
#define log_dbg(x...) logger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
|
||||
#define log_std(c, x...) logger(c, CRYPT_LOG_NORMAL, __FILE__, __LINE__, x)
|
||||
#define log_verbose(c, x...) logger(c, CRYPT_LOG_VERBOSE, __FILE__, __LINE__, x)
|
||||
@@ -199,5 +190,15 @@ int crypt_get_integrity_tag_size(struct crypt_device *cd);
|
||||
|
||||
int crypt_key_in_keyring(struct crypt_device *cd);
|
||||
void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring);
|
||||
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
|
||||
int crypt_use_keyring_for_vk(const struct crypt_device *cd);
|
||||
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description);
|
||||
|
||||
static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, uint16_t release)
|
||||
{
|
||||
return (uint64_t)release | ((uint64_t)patch << 16) | ((uint64_t)minor << 32) | ((uint64_t)major << 48);
|
||||
}
|
||||
|
||||
int kernel_version(uint64_t *kversion);
|
||||
|
||||
#endif /* INTERNAL_H */
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -48,7 +48,7 @@ extern "C" {
|
||||
struct crypt_device; /* crypt device handle */
|
||||
|
||||
/**
|
||||
* Initialize crypt device handle and check if provided device exists.
|
||||
* Initialize crypt device handle and check if the provided device exists.
|
||||
*
|
||||
* @param cd Returns pointer to crypt device handle
|
||||
* @param device Path to the backing device.
|
||||
@@ -59,7 +59,7 @@ struct crypt_device; /* crypt device handle */
|
||||
*
|
||||
* @return @e 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note Note that logging is not initialized here, possible messages uses
|
||||
* @note Note that logging is not initialized here, possible messages use
|
||||
* default log function.
|
||||
*/
|
||||
int crypt_init(struct crypt_device **cd, const char *device);
|
||||
@@ -116,7 +116,8 @@ void crypt_free(struct crypt_device *cd);
|
||||
* @param usrptr provided identification in callback
|
||||
* @param msg Message for user to confirm
|
||||
*
|
||||
* @note Current version of cryptsetup API requires confirmation only when UUID is being changed
|
||||
* @note Current version of cryptsetup API requires confirmation for UUID change and
|
||||
* LUKS header restore only.
|
||||
*/
|
||||
void crypt_set_confirm_callback(struct crypt_device *cd,
|
||||
int (*confirm)(const char *msg, void *usrptr),
|
||||
@@ -239,14 +240,25 @@ struct crypt_pbkdf_type {
|
||||
*
|
||||
* @return 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note For LUKS1, only PBKDF2 is suppported, other settings will be rejected.
|
||||
* @note For LUKS1, only PBKDF2 is supported, other settings will be rejected.
|
||||
* @note For non-LUKS context types the call succeeds, but PBKDF is not used.
|
||||
*/
|
||||
int crypt_set_pbkdf_type(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf);
|
||||
|
||||
/**
|
||||
* Get current default PBKDF (Password-Based Key Derivation Algorithm) for keyslots.
|
||||
* Get default PBKDF (Password-Based Key Derivation Algorithm) settings for keyslots.
|
||||
* Works only with LUKS device handles (both versions).
|
||||
*
|
||||
* @param type type of device (see @link crypt-type @endlink)
|
||||
*
|
||||
* @return struct on success or NULL value otherwise.
|
||||
*
|
||||
*/
|
||||
const struct crypt_pbkdf_type *crypt_get_pbkdf_default(const char *type);
|
||||
|
||||
/**
|
||||
* Get current PBKDF (Password-Based Key Derivation Algorithm) settings for keyslots.
|
||||
* Works only with LUKS device handles (both versions).
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
@@ -509,9 +521,9 @@ struct crypt_params_luks2 {
|
||||
*
|
||||
* @returns @e 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note Note that crypt_format does not enable any keyslot (in case of work with LUKS device),
|
||||
* but it stores volume key internally and subsequent crypt_keyslot_add_* calls can be used.
|
||||
* @note For VERITY @link crypt-type @endlink, only uuid parameter is used, others paramaters
|
||||
* @note Note that crypt_format does not create LUKS keyslot (any version). To create keyslot
|
||||
* call any crypt_keyslot_add_* function.
|
||||
* @note For VERITY @link crypt-type @endlink, only uuid parameter is used, other parameters
|
||||
* are ignored and verity specific attributes are set through mandatory params option.
|
||||
*/
|
||||
int crypt_format(struct crypt_device *cd,
|
||||
@@ -532,7 +544,14 @@ int crypt_format(struct crypt_device *cd,
|
||||
*
|
||||
* @returns 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note Currently, only LUKS1->LUKS2 conversion is supported
|
||||
* @note Currently, only LUKS1->LUKS2 and LUKS2->LUKS1 conversions are supported.
|
||||
* Not all LUKS2 devices may be converted back to LUKS1. To make such a conversion
|
||||
* possible all active LUKS2 keyslots must be in LUKS1 compatible mode (i.e. pbkdf
|
||||
* type must be PBKDF2) and device cannot be formatted with any authenticated
|
||||
* encryption mode.
|
||||
*
|
||||
* @note Device must be offline for conversion. UUID change is not possible for active
|
||||
* devices.
|
||||
*/
|
||||
int crypt_convert(struct crypt_device *cd,
|
||||
const char *type,
|
||||
@@ -567,10 +586,11 @@ int crypt_set_label(struct crypt_device *cd,
|
||||
const char *subsystem);
|
||||
|
||||
/**
|
||||
* Set or unset loading of volume keys via kernel keyring. When set to 'enabled'
|
||||
* library loads key in kernel keyring first and pass the key description to
|
||||
* dm-crypt instead of binary key copy. If set to 'disabled' library fall backs
|
||||
* to classical method loading volume key directly in dm-crypt target.
|
||||
* Enable or disable loading of volume keys via kernel keyring. When set to
|
||||
* 'enabled' library loads key in kernel keyring first and pass the key
|
||||
* description to dm-crypt instead of binary key copy. If set to 'disabled'
|
||||
* library fallbacks to old method of loading volume key directly in
|
||||
* dm-crypt target.
|
||||
*
|
||||
* @param cd crypt device handle, can be @e NULL
|
||||
* @param enable 0 to disable loading of volume keys via kernel keyring
|
||||
@@ -604,7 +624,7 @@ int crypt_load(struct crypt_device *cd,
|
||||
void *params);
|
||||
|
||||
/**
|
||||
* Try to repair crypt device on-disk header if invalid.
|
||||
* Try to repair crypt device LUKS on-disk header if invalid.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param requested_type @link crypt-type @endlink or @e NULL for all known
|
||||
@@ -612,6 +632,11 @@ int crypt_load(struct crypt_device *cd,
|
||||
*
|
||||
* @returns 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note For LUKS2 device crypt_repair bypass blkid checks and
|
||||
* perform auto-recovery even though there're third party device
|
||||
* signatures found by blkid probes. Currently the crypt_repair on LUKS2
|
||||
* works only if exactly one header checksum does not match or exactly
|
||||
* one header is missing.
|
||||
*/
|
||||
int crypt_repair(struct crypt_device *cd,
|
||||
const char *requested_type,
|
||||
@@ -627,10 +652,12 @@ int crypt_repair(struct crypt_device *cd,
|
||||
* @return @e 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note Most notably it returns -EPERM when device was activated with volume key
|
||||
* in kernel keyring and current device handle doesn't have verified key
|
||||
* in kernel keyring in the same time. Perform any crypt_activate_*()
|
||||
* operation with device name set to NULL to load verified volume key in
|
||||
* the keyring.
|
||||
* in kernel keyring and current device handle (context) doesn't have verified key
|
||||
* loaded in kernel. To load volume key for already active device use any of
|
||||
* @link crypt_activate_by_passphrase @endlink, @link crypt_activate_by_keyfile @endlink,
|
||||
* @link crypt_activate_by_keyfile_offset @endlink, @link crypt_activate_by_volume_key @endlink,
|
||||
* @link crypt_activate_by_keyring @endlink or @link crypt_activate_by_token @endlink with flag
|
||||
* @e CRYPT_ACTIVATE_KEYRING_KEY raised and @e name parameter set to @e NULL.
|
||||
*/
|
||||
int crypt_resize(struct crypt_device *cd,
|
||||
const char *name,
|
||||
@@ -657,7 +684,7 @@ int crypt_suspend(struct crypt_device *cd,
|
||||
* @param cd crypt device handle
|
||||
* @param name name of device to resume
|
||||
* @param keyslot requested keyslot or CRYPT_ANY_SLOT
|
||||
* @param passphrase passphrase used to unlock volume key, @e NULL for query
|
||||
* @param passphrase passphrase used to unlock volume key
|
||||
* @param passphrase_size size of @e passphrase (binary data)
|
||||
*
|
||||
* @return unlocked key slot number or negative errno otherwise.
|
||||
@@ -676,20 +703,31 @@ int crypt_resume_by_passphrase(struct crypt_device *cd,
|
||||
* @param cd crypt device handle
|
||||
* @param name name of device to resume
|
||||
* @param keyslot requested keyslot or CRYPT_ANY_SLOT
|
||||
* @param keyfile key file used to unlock volume key, @e NULL for passphrase query
|
||||
* @param keyfile key file used to unlock volume key
|
||||
* @param keyfile_size number of bytes to read from keyfile, 0 is unlimited
|
||||
* @param keyfile_offset number of bytes to skip at start of keyfile
|
||||
*
|
||||
* @return unlocked key slot number or negative errno otherwise.
|
||||
*/
|
||||
int crypt_resume_by_keyfile_device_offset(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
const char *keyfile,
|
||||
size_t keyfile_size,
|
||||
uint64_t keyfile_offset);
|
||||
|
||||
/**
|
||||
* Backward compatible crypt_resume_by_keyfile_device_offset() (with size_t offset).
|
||||
*/
|
||||
int crypt_resume_by_keyfile_offset(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
const char *keyfile,
|
||||
size_t keyfile_size,
|
||||
size_t keyfile_offset);
|
||||
|
||||
/**
|
||||
* Backward compatible crypt_resume_by_keyfile_offset() (without offset).
|
||||
* Backward compatible crypt_resume_by_keyfile_device_offset() (without offset).
|
||||
*/
|
||||
int crypt_resume_by_keyfile(struct crypt_device *cd,
|
||||
const char *name,
|
||||
@@ -714,9 +752,9 @@ int crypt_resume_by_keyfile(struct crypt_device *cd,
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param keyslot requested keyslot or @e CRYPT_ANY_SLOT
|
||||
* @param passphrase passphrase used to unlock volume key, @e NULL for query
|
||||
* @param passphrase passphrase used to unlock volume key
|
||||
* @param passphrase_size size of passphrase (binary data)
|
||||
* @param new_passphrase passphrase for new keyslot, @e NULL for query
|
||||
* @param new_passphrase passphrase for new keyslot
|
||||
* @param new_passphrase_size size of @e new_passphrase (binary data)
|
||||
*
|
||||
* @return allocated key slot number or negative errno otherwise.
|
||||
@@ -736,9 +774,9 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
|
||||
* @param cd crypt device handle
|
||||
* @param keyslot_old old keyslot or @e CRYPT_ANY_SLOT
|
||||
* @param keyslot_new new keyslot (can be the same as old)
|
||||
* @param passphrase passphrase used to unlock volume key, @e NULL for query
|
||||
* @param passphrase passphrase used to unlock volume key
|
||||
* @param passphrase_size size of passphrase (binary data)
|
||||
* @param new_passphrase passphrase for new keyslot, @e NULL for query
|
||||
* @param new_passphrase passphrase for new keyslot
|
||||
* @param new_passphrase_size size of @e new_passphrase (binary data)
|
||||
*
|
||||
* @return allocated key slot number or negative errno otherwise.
|
||||
@@ -762,15 +800,27 @@ int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param keyslot requested keyslot or @e CRYPT_ANY_SLOT
|
||||
* @param keyfile key file used to unlock volume key, @e NULL for passphrase query
|
||||
* @param keyfile key file used to unlock volume key
|
||||
* @param keyfile_size number of bytes to read from keyfile, @e 0 is unlimited
|
||||
* @param keyfile_offset number of bytes to skip at start of keyfile
|
||||
* @param new_keyfile keyfile for new keyslot, @e NULL for passphrase query
|
||||
* @param new_keyfile keyfile for new keyslot
|
||||
* @param new_keyfile_size number of bytes to read from @e new_keyfile, @e 0 is unlimited
|
||||
* @param new_keyfile_offset number of bytes to skip at start of new_keyfile
|
||||
*
|
||||
* @return allocated key slot number or negative errno otherwise.
|
||||
*/
|
||||
int crypt_keyslot_add_by_keyfile_device_offset(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *keyfile,
|
||||
size_t keyfile_size,
|
||||
uint64_t keyfile_offset,
|
||||
const char *new_keyfile,
|
||||
size_t new_keyfile_size,
|
||||
uint64_t new_keyfile_offset);
|
||||
|
||||
/**
|
||||
* Backward compatible crypt_keyslot_add_by_keyfile_device_offset() (with size_t offset).
|
||||
*/
|
||||
int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *keyfile,
|
||||
@@ -779,8 +829,9 @@ int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd,
|
||||
const char *new_keyfile,
|
||||
size_t new_keyfile_size,
|
||||
size_t new_keyfile_offset);
|
||||
|
||||
/**
|
||||
* Backward compatible crypt_keyslot_add_by_keyfile_offset() (without offset).
|
||||
* Backward compatible crypt_keyslot_add_by_keyfile_device_offset() (without offset).
|
||||
*/
|
||||
int crypt_keyslot_add_by_keyfile(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
@@ -798,7 +849,7 @@ int crypt_keyslot_add_by_keyfile(struct crypt_device *cd,
|
||||
* @param keyslot requested keyslot or CRYPT_ANY_SLOT
|
||||
* @param volume_key provided volume key or @e NULL if used after crypt_format
|
||||
* @param volume_key_size size of volume_key
|
||||
* @param passphrase passphrase for new keyslot, @e NULL for query
|
||||
* @param passphrase passphrase for new keyslot
|
||||
* @param passphrase_size size of passphrase
|
||||
*
|
||||
* @return allocated key slot number or negative errno otherwise.
|
||||
@@ -813,6 +864,9 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
|
||||
/** create keyslot with volume key not associated with current dm-crypt segment */
|
||||
#define CRYPT_VOLUME_KEY_NO_SEGMENT (1 << 0)
|
||||
|
||||
/** create keyslot with new volume key and assign it to current dm-crypt segment */
|
||||
#define CRYPT_VOLUME_KEY_SET (1 << 1)
|
||||
|
||||
/**
|
||||
* Add key slot using provided key.
|
||||
*
|
||||
@@ -822,17 +876,25 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
|
||||
* @param keyslot requested keyslot or CRYPT_ANY_SLOT
|
||||
* @param volume_key provided volume key or @e NULL (see note below)
|
||||
* @param volume_key_size size of volume_key
|
||||
* @param passphrase passphrase for new keyslot, @e NULL for query
|
||||
* @param passphrase passphrase for new keyslot
|
||||
* @param passphrase_size size of passphrase
|
||||
* @param flags key flags to set
|
||||
*
|
||||
* @return allocated key slot number or negative errno otherwise.
|
||||
*
|
||||
* @note in case volume_key is @e NULL following first matching rule will apply:
|
||||
* a) if cd is device handle used in crypt_format() by current process, the volume
|
||||
* key generated (passed) to crypt_format() will be stored in keyslot.
|
||||
* b) if CRYPT_VOLUME_KEY_NO_SEGMENT flag is raised the new volume_key will be
|
||||
* generated and stored in keyslot.
|
||||
* @li if cd is device handle used in crypt_format() by current process, the volume
|
||||
* key generated (or passed) in crypt_format() will be stored in keyslot.
|
||||
* @li if CRYPT_VOLUME_KEY_NO_SEGMENT flag is raised the new volume_key will be
|
||||
* generated and stored in keyslot. The keyslot will become unbound (unusable to
|
||||
* dm-crypt device activation).
|
||||
* @li fails with -EINVAL otherwise
|
||||
*
|
||||
* @warning CRYPT_VOLUME_KEY_SET flag force updates volume key. It is @b not @b reencryption!
|
||||
* By doing so you will most probably destroy your ciphertext data device. It's supposed
|
||||
* to be used only in wrapped keys scheme for key refresh process where real (inner) volume
|
||||
* key stays untouched. It may be involed on active @e keyslot which makes the (previously
|
||||
* unbound) keyslot new regular keyslot.
|
||||
*/
|
||||
int crypt_keyslot_add_by_key(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
@@ -894,6 +956,10 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
|
||||
#define CRYPT_ACTIVATE_RECOVERY (1 << 13)
|
||||
/** ignore persistently stored flags */
|
||||
#define CRYPT_ACTIVATE_IGNORE_PERSISTENT (1 << 14)
|
||||
/** dm-verity: check_at_most_once - check data blocks only the first time */
|
||||
#define CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE (1 << 15)
|
||||
/** allow activation check including unbound keyslots (kesylots without segments) */
|
||||
#define CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY (1 << 16)
|
||||
|
||||
/**
|
||||
* Active device runtime attributes
|
||||
@@ -916,8 +982,20 @@ struct crypt_active_device {
|
||||
*
|
||||
*/
|
||||
int crypt_get_active_device(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct crypt_active_device *cad);
|
||||
const char *name,
|
||||
struct crypt_active_device *cad);
|
||||
|
||||
/**
|
||||
* Get detected number of integrity failures.
|
||||
*
|
||||
* @param cd crypt device handle (can be @e NULL)
|
||||
* @param name name of active device
|
||||
*
|
||||
* @return number of integrity failures or @e 0 otherwise
|
||||
*
|
||||
*/
|
||||
uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
|
||||
const char *name);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@@ -958,7 +1036,7 @@ typedef enum {
|
||||
* stored persistently.
|
||||
*
|
||||
* @note Only requirements flags recognised by current library may be set.
|
||||
* CRYPT_REQUIREMENT_FLAG is illegal (output only) in set operation.
|
||||
* CRYPT_REQUIREMENT_UNKNOWN is illegal (output only) in set operation.
|
||||
*/
|
||||
int crypt_persistent_flags_set(struct crypt_device *cd,
|
||||
crypt_flags_type type,
|
||||
@@ -990,7 +1068,7 @@ int crypt_persistent_flags_get(struct crypt_device *cd,
|
||||
* @param cd crypt device handle
|
||||
* @param name name of device to create, if @e NULL only check passphrase
|
||||
* @param keyslot requested keyslot to check or @e CRYPT_ANY_SLOT
|
||||
* @param passphrase passphrase used to unlock volume key, @e NULL for query
|
||||
* @param passphrase passphrase used to unlock volume key
|
||||
* @param passphrase_size size of @e passphrase
|
||||
* @param flags activation flags
|
||||
*
|
||||
@@ -1016,6 +1094,17 @@ int crypt_activate_by_passphrase(struct crypt_device *cd,
|
||||
*
|
||||
* @return unlocked key slot number or negative errno otherwise.
|
||||
*/
|
||||
int crypt_activate_by_keyfile_device_offset(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
const char *keyfile,
|
||||
size_t keyfile_size,
|
||||
uint64_t keyfile_offset,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* Backward compatible crypt_activate_by_keyfile_device_offset() (with size_t offset).
|
||||
*/
|
||||
int crypt_activate_by_keyfile_offset(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
@@ -1023,8 +1112,9 @@ int crypt_activate_by_keyfile_offset(struct crypt_device *cd,
|
||||
size_t keyfile_size,
|
||||
size_t keyfile_offset,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* Backward compatible crypt_activate_by_keyfile_offset() (without offset).
|
||||
* Backward compatible crypt_activate_by_keyfile_device_offset() (without offset).
|
||||
*/
|
||||
int crypt_activate_by_keyfile(struct crypt_device *cd,
|
||||
const char *name,
|
||||
@@ -1036,7 +1126,6 @@ int crypt_activate_by_keyfile(struct crypt_device *cd,
|
||||
/**
|
||||
* Activate device using provided volume key.
|
||||
*
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param name name of device to create, if @e NULL only check volume key
|
||||
* @param volume_key provided volume key (or @e NULL to use internal)
|
||||
@@ -1063,7 +1152,6 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
|
||||
/**
|
||||
* Activate device using passphrase stored in kernel keyring.
|
||||
*
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param name name of device to create, if @e NULL only check passphrase in keyring
|
||||
* @param key_description kernel keyring key description library should look
|
||||
@@ -1129,7 +1217,7 @@ int crypt_deactivate(struct crypt_device *cd, const char *name);
|
||||
*
|
||||
* @return unlocked key slot number or negative errno otherwise.
|
||||
*
|
||||
* @note For TCRYPT cipher chain is the volume key concatenated
|
||||
* @note For TCRYPT cipher chain is the volume key concatenated
|
||||
* for all ciphers in chain.
|
||||
*/
|
||||
int crypt_volume_key_get(struct crypt_device *cd,
|
||||
@@ -1365,14 +1453,15 @@ typedef enum {
|
||||
CRYPT_SLOT_INVALID, /**< invalid keyslot */
|
||||
CRYPT_SLOT_INACTIVE, /**< keyslot is inactive (free) */
|
||||
CRYPT_SLOT_ACTIVE, /**< keyslot is active (used) */
|
||||
CRYPT_SLOT_ACTIVE_LAST /**< keylost is active (used)
|
||||
CRYPT_SLOT_ACTIVE_LAST,/**< keylost is active (used)
|
||||
* and last used at the same time */
|
||||
CRYPT_SLOT_UNBOUND /**< keyslot is active and not bound
|
||||
* to any crypt segment (LUKS2 only) */
|
||||
} crypt_keyslot_info;
|
||||
|
||||
/**
|
||||
* Get information about particular key slot.
|
||||
*
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param keyslot requested keyslot to check or CRYPT_ANY_SLOT
|
||||
*
|
||||
@@ -1438,6 +1527,18 @@ int crypt_keyslot_area(struct crypt_device *cd,
|
||||
uint64_t *offset,
|
||||
uint64_t *length);
|
||||
|
||||
/**
|
||||
* Get size (in bytes) of key for particular keyslot.
|
||||
* Use for LUKS2 unbound keyslots, for other keyslots it is the same as @ref crypt_get_volume_key_size
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param keyslot keyslot number
|
||||
*
|
||||
* @return volume key size or negative errno value otherwise.
|
||||
*
|
||||
*/
|
||||
int crypt_keyslot_get_key_size(struct crypt_device *cd, int keyslot);
|
||||
|
||||
/**
|
||||
* Get directory where mapped crypt devices are created
|
||||
*
|
||||
@@ -1469,7 +1570,6 @@ int crypt_header_backup(struct crypt_device *cd,
|
||||
/**
|
||||
* Restore header and keyslots from backup file.
|
||||
*
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param requested_type @link crypt-type @endlink or @e NULL for all known
|
||||
* @param backup_file file to restore header from
|
||||
@@ -1512,15 +1612,37 @@ void crypt_set_debug_level(int level);
|
||||
/**
|
||||
* Read keyfile
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param keyfile keyfile to read
|
||||
* @param key buffer for key
|
||||
* @param key_size_read size of read key
|
||||
* @param keyfile_offset key offset in keyfile
|
||||
* @param key_size exact key length to read from file or 0
|
||||
* @param flags keyfile read flags
|
||||
*
|
||||
* @return @e 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note If key_size is set to zero we read internal max length
|
||||
* and actual size read is returned via key_size_read parameter.
|
||||
*/
|
||||
int crypt_keyfile_device_read(struct crypt_device *cd,
|
||||
const char *keyfile,
|
||||
char **key, size_t *key_size_read,
|
||||
uint64_t keyfile_offset,
|
||||
size_t key_size,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* Backward compatible crypt_keyfile_device_read() (with size_t offset).
|
||||
*/
|
||||
int crypt_keyfile_read(struct crypt_device *cd,
|
||||
const char *keyfile,
|
||||
char **key, size_t *key_size_read,
|
||||
size_t keyfile_offset,
|
||||
size_t keyfile_size_max,
|
||||
uint32_t flags
|
||||
);
|
||||
/** No on-disk header (only hashes) */
|
||||
size_t key_size,
|
||||
uint32_t flags);
|
||||
|
||||
/** Read key only to the first end of line (\\n). */
|
||||
#define CRYPT_KEYFILE_STOP_EOL (1 << 0)
|
||||
/** @} */
|
||||
|
||||
@@ -1580,13 +1702,13 @@ int crypt_wipe(struct crypt_device *cd,
|
||||
* Utilities for handling tokens LUKS2
|
||||
* Token is a device or a method how to read password for particular keyslot
|
||||
* automatically. It can be chunk of data stored on hardware token or
|
||||
* just a metadata how to generate password.
|
||||
* just a metadata how to generate the password.
|
||||
*
|
||||
* @addtogroup crypt-tokens
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** iterate through all tokens */
|
||||
/** Iterate through all tokens */
|
||||
#define CRYPT_ANY_TOKEN -1
|
||||
|
||||
/**
|
||||
@@ -1612,7 +1734,7 @@ int crypt_token_json_get(struct crypt_device *cd,
|
||||
* @return allocated token id or negative errno otherwise.
|
||||
*
|
||||
* @note The buffer must be in proper JSON format and must contain at least
|
||||
* string "type" with slot type and array of string names "keyslots".
|
||||
* string "type" with slot type and an array of string names "keyslots".
|
||||
* Keyslots array contains assignments to particular slots and can be empty.
|
||||
*/
|
||||
int crypt_token_json_set(struct crypt_device *cd,
|
||||
@@ -1648,7 +1770,7 @@ typedef enum {
|
||||
crypt_token_info crypt_token_status(struct crypt_device *cd, int token, const char **type);
|
||||
|
||||
/**
|
||||
* LUKS2 keyring token paramaters.
|
||||
* LUKS2 keyring token parameters.
|
||||
*
|
||||
* @see crypt_token_builtin_set
|
||||
*
|
||||
@@ -1717,9 +1839,24 @@ int crypt_token_unassign_keyslot(struct crypt_device *cd,
|
||||
int token,
|
||||
int keyslot);
|
||||
|
||||
/**
|
||||
* Get info about token assignment to particular keyslot.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param token token id
|
||||
* @param keyslot keyslot
|
||||
*
|
||||
* @return 0 on success (token exists and is assigned to the keyslot),
|
||||
* -ENOENT if token is not assigned to a keyslot (token, keyslot
|
||||
* or both may be inactive) or other negative errno otherwise.
|
||||
*/
|
||||
int crypt_token_is_assigned(struct crypt_device *cd,
|
||||
int token,
|
||||
int keyslot);
|
||||
|
||||
/**
|
||||
* Token handler open function prototype.
|
||||
* This fuction retrieves password from a token and return allocated buffer
|
||||
* This function retrieves password from a token and return allocated buffer
|
||||
* containing this password. This buffer has to be deallocated by calling
|
||||
* free() function and content should be wiped before deallocation.
|
||||
*
|
||||
@@ -1749,7 +1886,7 @@ typedef void (*crypt_token_buffer_free_func) (void *buffer, size_t buffer_len);
|
||||
|
||||
/**
|
||||
* Token handler validate function prototype.
|
||||
* This fuction validates JSON representation of user defined token for additional data
|
||||
* This function validates JSON representation of user defined token for additional data
|
||||
* specific for its token type. If defined in the handler, it's called
|
||||
* during @link crypt_activate_by_token @endlink. It may also be called during
|
||||
* @link crypt_token_json_set @endlink when appropriate token handler was registered before
|
||||
@@ -1762,7 +1899,7 @@ typedef int (*crypt_token_validate_func) (struct crypt_device *cd, const char *j
|
||||
|
||||
/**
|
||||
* Token handler dump function prototype.
|
||||
* This fuction is supposed to print token implementation specific details. It gets
|
||||
* This function is supposed to print token implementation specific details. It gets
|
||||
* called during @link crypt_dump @endlink if token handler was registered before.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
|
||||
@@ -22,12 +22,14 @@ CRYPTSETUP_2.0 {
|
||||
crypt_resume_by_passphrase;
|
||||
crypt_resume_by_keyfile;
|
||||
crypt_resume_by_keyfile_offset;
|
||||
crypt_resume_by_keyfile_device_offset;
|
||||
crypt_free;
|
||||
|
||||
crypt_keyslot_add_by_passphrase;
|
||||
crypt_keyslot_change_by_passphrase;
|
||||
crypt_keyslot_add_by_keyfile;
|
||||
crypt_keyslot_add_by_keyfile_offset;
|
||||
crypt_keyslot_add_by_keyfile_device_offset;
|
||||
crypt_keyslot_add_by_volume_key;
|
||||
crypt_keyslot_add_by_key;
|
||||
|
||||
@@ -41,6 +43,7 @@ CRYPTSETUP_2.0 {
|
||||
crypt_token_luks2_keyring_set;
|
||||
crypt_token_assign_keyslot;
|
||||
crypt_token_unassign_keyslot;
|
||||
crypt_token_is_assigned;
|
||||
crypt_token_register;
|
||||
|
||||
crypt_activate_by_token;
|
||||
@@ -49,6 +52,7 @@ CRYPTSETUP_2.0 {
|
||||
crypt_activate_by_passphrase;
|
||||
crypt_activate_by_keyfile;
|
||||
crypt_activate_by_keyfile_offset;
|
||||
crypt_activate_by_keyfile_device_offset;
|
||||
crypt_activate_by_volume_key;
|
||||
crypt_activate_by_keyring;
|
||||
crypt_deactivate;
|
||||
@@ -73,6 +77,7 @@ CRYPTSETUP_2.0 {
|
||||
|
||||
crypt_get_type;
|
||||
crypt_get_active_device;
|
||||
crypt_get_active_integrity_failures;
|
||||
crypt_persistent_flags_set;
|
||||
crypt_persistent_flags_get;
|
||||
|
||||
@@ -80,10 +85,12 @@ CRYPTSETUP_2.0 {
|
||||
crypt_get_rng_type;
|
||||
crypt_set_pbkdf_type;
|
||||
crypt_get_pbkdf_type;
|
||||
crypt_get_pbkdf_default;
|
||||
|
||||
crypt_keyslot_max;
|
||||
crypt_keyslot_area;
|
||||
crypt_keyslot_status;
|
||||
crypt_keyslot_get_key_size;
|
||||
crypt_get_dir;
|
||||
crypt_set_debug_level;
|
||||
crypt_log;
|
||||
@@ -92,6 +99,7 @@ CRYPTSETUP_2.0 {
|
||||
crypt_header_restore;
|
||||
|
||||
crypt_keyfile_read;
|
||||
crypt_keyfile_device_read;
|
||||
|
||||
crypt_wipe;
|
||||
local:
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -96,7 +96,6 @@ static void set_dm_error(int level,
|
||||
if (vasprintf(&msg, f, va) > 0) {
|
||||
if (level < 4 && !_quiet_log) {
|
||||
log_err(_context, "%s", msg);
|
||||
log_err(_context, "\n");
|
||||
} else {
|
||||
/* We do not use DM visual stack backtrace here */
|
||||
if (strncmp(msg, "<backtrace>", 11))
|
||||
@@ -109,13 +108,16 @@ static void set_dm_error(int level,
|
||||
|
||||
static int _dm_simple(int task, const char *name, int udev_wait);
|
||||
|
||||
static int _dm_satisfies_version(unsigned target_maj, unsigned target_min,
|
||||
unsigned actual_maj, unsigned actual_min)
|
||||
static int _dm_satisfies_version(unsigned target_maj, unsigned target_min, unsigned target_patch,
|
||||
unsigned actual_maj, unsigned actual_min, unsigned actual_patch)
|
||||
{
|
||||
if (actual_maj > target_maj)
|
||||
return 1;
|
||||
|
||||
if (actual_maj == target_maj && actual_min >= target_min)
|
||||
if (actual_maj == target_maj && actual_min > target_min)
|
||||
return 1;
|
||||
|
||||
if (actual_maj == target_maj && actual_min == target_min && actual_patch >= target_patch)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -131,33 +133,33 @@ static void _dm_set_crypt_compat(unsigned crypt_maj,
|
||||
log_dbg("Detected dm-crypt version %i.%i.%i.",
|
||||
crypt_maj, crypt_min, crypt_patch);
|
||||
|
||||
if (_dm_satisfies_version(1, 2, crypt_maj, crypt_min))
|
||||
if (_dm_satisfies_version(1, 2, 0, crypt_maj, crypt_min, crypt_patch))
|
||||
_dm_flags |= DM_KEY_WIPE_SUPPORTED;
|
||||
else
|
||||
log_dbg("Suspend and resume disabled, no wipe key support.");
|
||||
|
||||
if (_dm_satisfies_version(1, 10, crypt_maj, crypt_min))
|
||||
if (_dm_satisfies_version(1, 10, 0, crypt_maj, crypt_min, crypt_patch))
|
||||
_dm_flags |= DM_LMK_SUPPORTED;
|
||||
|
||||
/* not perfect, 2.6.33 supports with 1.7.0 */
|
||||
if (_dm_satisfies_version(1, 8, crypt_maj, crypt_min))
|
||||
if (_dm_satisfies_version(1, 8, 0, crypt_maj, crypt_min, crypt_patch))
|
||||
_dm_flags |= DM_PLAIN64_SUPPORTED;
|
||||
|
||||
if (_dm_satisfies_version(1, 11, crypt_maj, crypt_min))
|
||||
if (_dm_satisfies_version(1, 11, 0, crypt_maj, crypt_min, crypt_patch))
|
||||
_dm_flags |= DM_DISCARDS_SUPPORTED;
|
||||
|
||||
if (_dm_satisfies_version(1, 13, crypt_maj, crypt_min))
|
||||
if (_dm_satisfies_version(1, 13, 0, crypt_maj, crypt_min, crypt_patch))
|
||||
_dm_flags |= DM_TCW_SUPPORTED;
|
||||
|
||||
if (_dm_satisfies_version(1, 14, crypt_maj, crypt_min)) {
|
||||
if (_dm_satisfies_version(1, 14, 0, crypt_maj, crypt_min, crypt_patch)) {
|
||||
_dm_flags |= DM_SAME_CPU_CRYPT_SUPPORTED;
|
||||
_dm_flags |= DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED;
|
||||
}
|
||||
|
||||
if (_dm_satisfies_version(1, 15, crypt_maj, crypt_min))
|
||||
if (_dm_satisfies_version(1, 18, 1, crypt_maj, crypt_min, crypt_patch))
|
||||
_dm_flags |= DM_KERNEL_KEYRING_SUPPORTED;
|
||||
|
||||
if (_dm_satisfies_version(1, 17, crypt_maj, crypt_min)) {
|
||||
if (_dm_satisfies_version(1, 17, 0, crypt_maj, crypt_min, crypt_patch)) {
|
||||
_dm_flags |= DM_SECTOR_SIZE_SUPPORTED;
|
||||
_dm_flags |= DM_CAPI_STRING_SUPPORTED;
|
||||
}
|
||||
@@ -182,8 +184,9 @@ static void _dm_set_verity_compat(unsigned verity_maj,
|
||||
* ignore_zero_blocks since 1.3 (kernel 4.5)
|
||||
* (but some dm-verity targets 1.2 don't support it)
|
||||
* FEC is added in 1.3 as well.
|
||||
* Check at most once is added in 1.4 (kernel 4.17).
|
||||
*/
|
||||
if (_dm_satisfies_version(1, 3, verity_maj, verity_min)) {
|
||||
if (_dm_satisfies_version(1, 3, 0, verity_maj, verity_min, verity_patch)) {
|
||||
_dm_flags |= DM_VERITY_ON_CORRUPTION_SUPPORTED;
|
||||
_dm_flags |= DM_VERITY_FEC_SUPPORTED;
|
||||
}
|
||||
@@ -238,10 +241,10 @@ static int _dm_check_versions(dm_target_type target_type)
|
||||
goto out;
|
||||
log_dbg("Detected dm-ioctl version %u.%u.%u.", dm_maj, dm_min, dm_patch);
|
||||
|
||||
if (_dm_satisfies_version(4, 20, dm_maj, dm_min))
|
||||
if (_dm_satisfies_version(4, 20, 0, dm_maj, dm_min, dm_patch))
|
||||
_dm_flags |= DM_SECURE_SUPPORTED;
|
||||
#if HAVE_DECL_DM_TASK_DEFERRED_REMOVE
|
||||
if (_dm_satisfies_version(4, 27, dm_maj, dm_min))
|
||||
if (_dm_satisfies_version(4, 27, 0, dm_maj, dm_min, dm_patch))
|
||||
_dm_flags |= DM_DEFERRED_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
@@ -326,10 +329,10 @@ static int dm_init_context(struct crypt_device *cd, dm_target_type target)
|
||||
if (!_dm_check_versions(target)) {
|
||||
if (getuid() || geteuid())
|
||||
log_err(cd, _("Cannot initialize device-mapper, "
|
||||
"running as non-root user.\n"));
|
||||
"running as non-root user."));
|
||||
else
|
||||
log_err(cd, _("Cannot initialize device-mapper. "
|
||||
"Is dm_mod kernel module loaded?\n"));
|
||||
"Is dm_mod kernel module loaded?"));
|
||||
_context = NULL;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
@@ -454,7 +457,7 @@ static int cipher_c2dm(const char *org_c, const char *org_i, unsigned tag_size,
|
||||
static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char *i_dm)
|
||||
{
|
||||
char cipher[CLEN], mode[CLEN], iv[CLEN], auth[CLEN];
|
||||
char tmp[CAPIL], capi[CAPIL];
|
||||
char tmp[CAPIL*2], capi[CAPIL];
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
@@ -520,7 +523,7 @@ static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd, uint32_t fl
|
||||
{
|
||||
int r, max_size, null_cipher = 0, num_options = 0, keystr_len = 0;
|
||||
char *params, *hexkey;
|
||||
char sector_feature[32], features[256], integrity_dm[256], cipher_dm[256];
|
||||
char sector_feature[32], features[512], integrity_dm[256], cipher_dm[256];
|
||||
|
||||
if (!dmd)
|
||||
return NULL;
|
||||
@@ -619,6 +622,8 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
|
||||
num_options++;
|
||||
if (flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS)
|
||||
num_options++;
|
||||
if (flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE)
|
||||
num_options++;
|
||||
|
||||
if (dmd->u.verity.fec_device) {
|
||||
num_options += 8;
|
||||
@@ -630,10 +635,11 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
|
||||
*fec_features = '\0';
|
||||
|
||||
if (num_options)
|
||||
snprintf(features, sizeof(features)-1, " %d%s%s%s", num_options,
|
||||
snprintf(features, sizeof(features)-1, " %d%s%s%s%s", num_options,
|
||||
(flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "",
|
||||
(flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) ? " restart_on_corruption" : "",
|
||||
(flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "");
|
||||
(flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "",
|
||||
(flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? " check_at_most_once" : "");
|
||||
else
|
||||
*features = '\0';
|
||||
|
||||
@@ -929,7 +935,7 @@ int dm_remove_device(struct crypt_device *cd, const char *name, uint32_t flags)
|
||||
|
||||
dm_flags(DM_UNKNOWN, &dmt_flags);
|
||||
if (deferred && !(dmt_flags & DM_DEFERRED_SUPPORTED)) {
|
||||
log_err(cd, _("Requested deferred flag is not supported.\n"));
|
||||
log_err(cd, _("Requested deferred flag is not supported."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -994,7 +1000,7 @@ static int dm_prepare_uuid(const char *name, const char *type, const char *uuid,
|
||||
|
||||
log_dbg("DM-UUID is %s", buf);
|
||||
if (i >= buflen)
|
||||
log_err(NULL, _("DM-UUID for device %s was truncated.\n"), name);
|
||||
log_err(NULL, _("DM-UUID for device %s was truncated."), name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1155,11 +1161,19 @@ static int check_retry(uint32_t *dmd_flags, uint32_t dmt_flags)
|
||||
/* If kernel keyring is not supported load key directly in dm-crypt */
|
||||
if ((*dmd_flags & CRYPT_ACTIVATE_KEYRING_KEY) &&
|
||||
!(dmt_flags & DM_KERNEL_KEYRING_SUPPORTED)) {
|
||||
log_dbg("dm-crypt doesn't suport kernel keyring");
|
||||
log_dbg("dm-crypt doesn't support kernel keyring");
|
||||
*dmd_flags = *dmd_flags & ~CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
/* Drop performance options if not supported */
|
||||
if ((*dmd_flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT | CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS)) &&
|
||||
!(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED | DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED))) {
|
||||
log_dbg("dm-crypt doesn't support performance options");
|
||||
*dmd_flags = *dmd_flags & ~(CRYPT_ACTIVATE_SAME_CPU_CRYPT | CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1206,23 +1220,24 @@ int dm_create_device(struct crypt_device *cd, const char *name,
|
||||
if (r == -EINVAL &&
|
||||
dmd_flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) &&
|
||||
!(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED)))
|
||||
log_err(cd, _("Requested dm-crypt performance options are not supported.\n"));
|
||||
log_err(cd, _("Requested dm-crypt performance options are not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd_flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
|
||||
CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
|
||||
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) &&
|
||||
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS|
|
||||
CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) &&
|
||||
!(dmt_flags & DM_VERITY_ON_CORRUPTION_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-verity data corruption handling options are not supported.\n"));
|
||||
log_err(cd, _("Requested dm-verity data corruption handling options are not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->target == DM_VERITY && dmd->u.verity.fec_device &&
|
||||
!(dmt_flags & DM_VERITY_FEC_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-verity FEC options are not supported.\n"));
|
||||
log_err(cd, _("Requested dm-verity FEC options are not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->target == DM_CRYPT) {
|
||||
if (dmd->u.crypt.integrity && !(dmt_flags & DM_INTEGRITY_SUPPORTED))
|
||||
log_err(cd, _("Requested data integrity options are not supported.\n"));
|
||||
log_err(cd, _("Requested data integrity options are not supported."));
|
||||
if (dmd->u.crypt.sector_size != SECTOR_SIZE && !(dmt_flags & DM_SECTOR_SIZE_SUPPORTED))
|
||||
log_err(cd, _("Requested sector_size option is not supported.\n"));
|
||||
log_err(cd, _("Requested sector_size option is not supported."));
|
||||
}
|
||||
out:
|
||||
crypt_safe_free(table_params);
|
||||
@@ -1288,7 +1303,7 @@ int dm_status_device(struct crypt_device *cd, const char *name)
|
||||
struct stat st;
|
||||
|
||||
/* libdevmapper is too clever and handles
|
||||
* path argument differenly with error.
|
||||
* path argument differently with error.
|
||||
* Fail early here if parameter is non-existent path.
|
||||
*/
|
||||
if (strchr(name, '/') && stat(name, &st) < 0)
|
||||
@@ -1349,6 +1364,29 @@ int dm_status_verity_ok(struct crypt_device *cd, const char *name)
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_status_integrity_failures(struct crypt_device *cd, const char *name, uint64_t *count)
|
||||
{
|
||||
int r;
|
||||
struct dm_info dmi;
|
||||
char *status_line = NULL;
|
||||
|
||||
if (dm_init_context(cd, DM_INTEGRITY))
|
||||
return -ENOTSUP;
|
||||
|
||||
r = dm_status_dmi(name, &dmi, DM_INTEGRITY_TARGET, &status_line);
|
||||
if (r < 0 || !status_line) {
|
||||
free(status_line);
|
||||
return r;
|
||||
}
|
||||
|
||||
log_dbg("Integrity volume %s failure status is %s.", name, status_line ?: "");
|
||||
*count = strtoull(status_line, NULL, 10);
|
||||
free(status_line);
|
||||
dm_exit_context();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME use hex wrapper, user val wrappers for line parsing */
|
||||
static int _dm_query_crypt(uint32_t get_flags,
|
||||
struct dm_info *dmi,
|
||||
@@ -1479,11 +1517,16 @@ static int _dm_query_crypt(uint32_t get_flags,
|
||||
|
||||
if (get_flags & DM_ACTIVE_CRYPT_KEY) {
|
||||
if (key_[0] == ':') {
|
||||
key_desc = strdup(strpbrk(strpbrk(key_ + 1, ":") + 1, ":") + 1);
|
||||
/* :<key_size>:<key_type>:<key_description> */
|
||||
key_desc = NULL;
|
||||
endp = strpbrk(key_ + 1, ":");
|
||||
if (endp)
|
||||
key_desc = strpbrk(endp + 1, ":");
|
||||
if (!key_desc) {
|
||||
r = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
key_desc++;
|
||||
crypt_volume_key_set_description(vk, key_desc);
|
||||
} else {
|
||||
buffer[2] = '\0';
|
||||
@@ -1673,6 +1716,8 @@ static int _dm_query_verity(uint32_t get_flags,
|
||||
dmd->flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION;
|
||||
else if (!strcasecmp(arg, "ignore_zero_blocks"))
|
||||
dmd->flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS;
|
||||
else if (!strcasecmp(arg, "check_at_most_once"))
|
||||
dmd->flags |= CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE;
|
||||
else if (!strcasecmp(arg, "use_fec_from_device")) {
|
||||
str = strsep(¶ms, " ");
|
||||
str2 = crypt_lookup_dev(str);
|
||||
@@ -1683,9 +1728,10 @@ static int _dm_query_verity(uint32_t get_flags,
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (vp)
|
||||
if (vp) {
|
||||
free(fec_dev_str);
|
||||
fec_dev_str = str2;
|
||||
else
|
||||
} else
|
||||
free(str2);
|
||||
i++;
|
||||
} else if (!strcasecmp(arg, "fec_start")) {
|
||||
@@ -2026,6 +2072,23 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_suspend_device(struct crypt_device *cd, const char *name)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (dm_init_context(cd, DM_UNKNOWN))
|
||||
return -ENOTSUP;
|
||||
|
||||
if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0))
|
||||
r = -EINVAL;
|
||||
else
|
||||
r = 0;
|
||||
|
||||
dm_exit_context();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name)
|
||||
{
|
||||
uint32_t dmt_flags;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* loop-AES compatible volume handling
|
||||
*
|
||||
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2017, Milan Broz
|
||||
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -87,12 +87,12 @@ static int hash_keys(struct crypt_device *cd,
|
||||
tweak = get_tweak(keys_count);
|
||||
|
||||
if (!keys_count || !key_len_output || !hash_name || !key_len_input) {
|
||||
log_err(cd, _("Key processing error (using hash %s).\n"),
|
||||
log_err(cd, _("Key processing error (using hash %s)."),
|
||||
hash_name ?: "[none]");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*vk = crypt_alloc_volume_key(key_len_output * keys_count, NULL);
|
||||
*vk = crypt_alloc_volume_key((size_t)key_len_output * keys_count, NULL);
|
||||
if (!*vk)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -165,7 +165,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
|
||||
}
|
||||
if (offset == buffer_len) {
|
||||
log_dbg("Unterminated key #%d in keyfile.", key_index);
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected.\n"));
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected."));
|
||||
return -EINVAL;
|
||||
}
|
||||
while (offset < buffer_len && !buffer[offset])
|
||||
@@ -185,7 +185,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
|
||||
|
||||
if (offset != buffer_len || key_len == 0 ||
|
||||
(key_index != 1 && key_index !=64 && key_index != 65)) {
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected.\n"));
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ int LOOPAES_activate(struct crypt_device *cd,
|
||||
|
||||
if (r < 0 && !dm_flags(DM_CRYPT, &dmc_flags) &&
|
||||
(dmc_flags & req_flags) != req_flags) {
|
||||
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n"));
|
||||
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping."));
|
||||
r = -ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* loop-AES compatible volume handling
|
||||
*
|
||||
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2017, Milan Broz
|
||||
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -22,6 +22,7 @@
|
||||
#ifndef _LOOPAES_H
|
||||
#define _LOOPAES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct crypt_device;
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
* AFsplitter - Anti forensic information splitter
|
||||
*
|
||||
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* AFsplitter diffuses information over a large stripe of data,
|
||||
* therefor supporting secure data destruction.
|
||||
* therefore supporting secure data destruction.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
* AFsplitter - Anti forensic information splitter
|
||||
*
|
||||
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* AFsplitter diffuses information over a large stripe of data,
|
||||
* therefor supporting secure data destruction.
|
||||
* therefore supporting secure data destruction.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,6 +24,8 @@
|
||||
#ifndef INCLUDED_CRYPTSETUP_LUKS_AF_H
|
||||
#define INCLUDED_CRYPTSETUP_LUKS_AF_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* AF_split operates on src and produces information split data in
|
||||
* dst. src is assumed to be of the length blocksize. The data stripe
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* LUKS - Linux Unified Key Setup
|
||||
*
|
||||
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "luks.h"
|
||||
@@ -30,17 +31,19 @@
|
||||
static void _error_hint(struct crypt_device *ctx, const char *device,
|
||||
const char *cipher, const char *mode, size_t keyLength)
|
||||
{
|
||||
char cipher_spec[MAX_CIPHER_LEN * 3];
|
||||
char *c, cipher_spec[MAX_CIPHER_LEN * 3];
|
||||
|
||||
if (snprintf(cipher_spec, sizeof(cipher_spec), "%s-%s", cipher, mode) < 0)
|
||||
return;
|
||||
|
||||
log_err(ctx, _("Failed to setup dm-crypt key mapping for device %s.\n"
|
||||
"Check that kernel supports %s cipher (check syslog for more info).\n"),
|
||||
"Check that kernel supports %s cipher (check syslog for more info)."),
|
||||
device, cipher_spec);
|
||||
|
||||
if (!strncmp(mode, "xts", 3) && (keyLength != 256 && keyLength != 512))
|
||||
log_err(ctx, _("Key size in XTS mode must be 256 or 512 bits.\n"));
|
||||
log_err(ctx, _("Key size in XTS mode must be 256 or 512 bits."));
|
||||
else if (!(c = strchr(mode, '-')) || strlen(c) < 4)
|
||||
log_err(ctx, _("Cipher specification should be in [cipher]-[mode]-[iv] format."));
|
||||
}
|
||||
|
||||
static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
@@ -67,7 +70,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
}
|
||||
};
|
||||
int r, devfd = -1;
|
||||
size_t bsize, alignment;
|
||||
size_t bsize, keyslot_alignment, alignment;
|
||||
|
||||
log_dbg("Using dmcrypt to access keyslot area.");
|
||||
|
||||
@@ -76,7 +79,11 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
if (!bsize || !alignment)
|
||||
return -EINVAL;
|
||||
|
||||
dmd.size = size_round_up(srcLength, bsize) / SECTOR_SIZE;
|
||||
if (bsize > LUKS_ALIGN_KEYSLOTS)
|
||||
keyslot_alignment = LUKS_ALIGN_KEYSLOTS;
|
||||
else
|
||||
keyslot_alignment = bsize;
|
||||
dmd.size = size_round_up(srcLength, keyslot_alignment) / SECTOR_SIZE;
|
||||
|
||||
if (mode == O_RDONLY)
|
||||
dmd.flags |= CRYPT_ACTIVATE_READONLY;
|
||||
@@ -91,13 +98,13 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
r = device_block_adjust(ctx, dmd.data_device, DEV_OK,
|
||||
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
|
||||
if (r < 0) {
|
||||
log_err(ctx, _("Device %s doesn't exist or access denied.\n"),
|
||||
log_err(ctx, _("Device %s doesn't exist or access denied."),
|
||||
device_path(dmd.data_device));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (mode != O_RDONLY && dmd.flags & CRYPT_ACTIVATE_READONLY) {
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied."),
|
||||
device_path(dmd.data_device));
|
||||
return -EACCES;
|
||||
}
|
||||
@@ -112,14 +119,14 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
|
||||
devfd = open(path, mode | O_DIRECT | O_SYNC);
|
||||
if (devfd == -1) {
|
||||
log_err(ctx, _("Failed to open temporary keystore device.\n"));
|
||||
log_err(ctx, _("Failed to open temporary keystore device."));
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = func(devfd, bsize, alignment, src, srcLength);
|
||||
if (r < 0) {
|
||||
log_err(ctx, _("Failed to access temporary keystore device.\n"));
|
||||
log_err(ctx, _("Failed to access temporary keystore device."));
|
||||
r = -EIO;
|
||||
} else
|
||||
r = 0;
|
||||
@@ -179,9 +186,9 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
if (devfd < 0)
|
||||
goto out;
|
||||
|
||||
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
|
||||
write_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), src, srcLength) == -1)
|
||||
if (write_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), src, srcLength,
|
||||
sector * SECTOR_SIZE) < 0)
|
||||
goto out;
|
||||
|
||||
r = 0;
|
||||
@@ -189,7 +196,7 @@ out:
|
||||
if (devfd >= 0)
|
||||
close(devfd);
|
||||
if (r)
|
||||
log_err(ctx, _("IO error while encrypting keyslot.\n"));
|
||||
log_err(ctx, _("IO error while encrypting keyslot."));
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -235,9 +242,9 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
if (devfd < 0)
|
||||
goto bad;
|
||||
|
||||
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
|
||||
read_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), dst, dstLength) == -1)
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), dst, dstLength,
|
||||
sector * SECTOR_SIZE) < 0)
|
||||
goto bad;
|
||||
|
||||
close(devfd);
|
||||
@@ -251,7 +258,7 @@ bad:
|
||||
if (devfd >= 0)
|
||||
close(devfd);
|
||||
|
||||
log_err(ctx, _("IO error while decrypting keyslot.\n"));
|
||||
log_err(ctx, _("IO error while decrypting keyslot."));
|
||||
crypt_storage_destroy(s);
|
||||
|
||||
return r;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* LUKS - Linux Unified Key Setup
|
||||
*
|
||||
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2013-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2013-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -125,7 +125,7 @@ static int LUKS_check_device_size(struct crypt_device *ctx, const struct luks_ph
|
||||
if (falloc && !device_fallocate(device, hdr_sectors << SECTOR_SHIFT))
|
||||
return 0;
|
||||
|
||||
log_err(ctx, _("Device %s is too small. (LUKS requires at least %" PRIu64 " bytes.)\n"),
|
||||
log_err(ctx, _("Device %s is too small. (LUKS1 requires at least %" PRIu64 " bytes.)"),
|
||||
device_path(device), hdr_sectors * SECTOR_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
|
||||
if (phdr->keyblock[i].stripes != LUKS_STRIPES) {
|
||||
log_dbg("Invalid stripes count %u in keyslot %u.",
|
||||
phdr->keyblock[i].stripes, i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
|
||||
if (phdr->keyblock[i].keyMaterialOffset * SECTOR_SIZE < sizeof(*phdr)) {
|
||||
log_dbg("Invalid offset %u in keyslot %u.",
|
||||
phdr->keyblock[i].keyMaterialOffset, i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
|
||||
log_dbg("Invalid offset %u in keyslot %u (beyond data area offset %u).",
|
||||
phdr->keyblock[i].keyMaterialOffset, i,
|
||||
phdr->payloadOffset);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
|
||||
phdr->keyblock[i].keyMaterialOffset,
|
||||
phdr->keyblock[i].stripes,
|
||||
i, phdr->payloadOffset);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -189,7 +189,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
|
||||
if (phdr->keyblock[next].keyMaterialOffset <
|
||||
(phdr->keyblock[prev].keyMaterialOffset + secs_per_stripes)) {
|
||||
log_dbg("Not enough space in LUKS keyslot %d.", prev);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), prev);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid."), prev);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -242,7 +242,7 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
|
||||
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
if (devfd < 0) {
|
||||
log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device_path(device));
|
||||
log_err(ctx, _("Device %s is not a valid LUKS device."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -261,14 +261,14 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
|
||||
devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
|
||||
if (devfd == -1) {
|
||||
if (errno == EEXIST)
|
||||
log_err(ctx, _("Requested header backup file %s already exists.\n"), backup_file);
|
||||
log_err(ctx, _("Requested header backup file %s already exists."), backup_file);
|
||||
else
|
||||
log_err(ctx, _("Cannot create header backup file %s.\n"), backup_file);
|
||||
log_err(ctx, _("Cannot create header backup file %s."), backup_file);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (write_buffer(devfd, buffer, buffer_size) < (ssize_t)buffer_size) {
|
||||
log_err(ctx, _("Cannot write header backup file %s.\n"), backup_file);
|
||||
log_err(ctx, _("Cannot write header backup file %s."), backup_file);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
@@ -301,7 +301,7 @@ int LUKS_hdr_restore(
|
||||
buffer_size = LUKS_device_sectors(&hdr_file) << SECTOR_SHIFT;
|
||||
|
||||
if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) {
|
||||
log_err(ctx, _("Backup file doesn't contain valid LUKS header.\n"));
|
||||
log_err(ctx, _("Backup file doesn't contain valid LUKS header."));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -314,13 +314,13 @@ int LUKS_hdr_restore(
|
||||
|
||||
devfd = open(backup_file, O_RDONLY);
|
||||
if (devfd == -1) {
|
||||
log_err(ctx, _("Cannot open header backup file %s.\n"), backup_file);
|
||||
log_err(ctx, _("Cannot open header backup file %s."), backup_file);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (read_buffer(devfd, buffer, buffer_size) < buffer_size) {
|
||||
log_err(ctx, _("Cannot read header backup file %s.\n"), backup_file);
|
||||
log_err(ctx, _("Cannot read header backup file %s."), backup_file);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
@@ -332,7 +332,7 @@ int LUKS_hdr_restore(
|
||||
log_dbg("Device %s already contains LUKS header, checking UUID and offset.", device_path(device));
|
||||
if(hdr->payloadOffset != hdr_file.payloadOffset ||
|
||||
hdr->keyBytes != hdr_file.keyBytes) {
|
||||
log_err(ctx, _("Data offset or key size differs on device and backup, restore failed.\n"));
|
||||
log_err(ctx, _("Data offset or key size differs on device and backup, restore failed."));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -359,10 +359,10 @@ int LUKS_hdr_restore(
|
||||
devfd = device_open(device, O_RDWR);
|
||||
if (devfd < 0) {
|
||||
if (errno == EACCES)
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied."),
|
||||
device_path(device));
|
||||
else
|
||||
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(ctx, _("Cannot open device %s."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -393,18 +393,22 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
int i, bad, r, need_write = 0;
|
||||
|
||||
if (phdr->keyBytes != 16 && phdr->keyBytes != 32 && phdr->keyBytes != 64) {
|
||||
log_err(ctx, _("Non standard key size, manual repair required.\n"));
|
||||
log_err(ctx, _("Non standard key size, manual repair required."));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* cryptsetup 1.0 did not align to 4k, cannot repair this one */
|
||||
if (LUKS_keyslots_offset(phdr) < (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
|
||||
log_err(ctx, _("Non standard keyslots alignment, manual repair required.\n"));
|
||||
log_err(ctx, _("Non standard keyslots alignment, manual repair required."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS_check_cipher(ctx, phdr->keyBytes, phdr->cipherName, phdr->cipherMode);
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
|
||||
vk = crypt_alloc_volume_key(phdr->keyBytes, NULL);
|
||||
|
||||
log_verbose(ctx, _("Repairing keyslots.\n"));
|
||||
log_verbose(ctx, _("Repairing keyslots."));
|
||||
|
||||
log_dbg("Generating second header with the same parameters for check.");
|
||||
/* cipherName, cipherMode, hashSpec, uuid are already null terminated */
|
||||
@@ -424,7 +428,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
|
||||
bad = 0;
|
||||
if (phdr->keyblock[i].keyMaterialOffset != temp_phdr.keyblock[i].keyMaterialOffset) {
|
||||
log_err(ctx, _("Keyslot %i: offset repaired (%u -> %u).\n"), i,
|
||||
log_err(ctx, _("Keyslot %i: offset repaired (%u -> %u)."), i,
|
||||
(unsigned)phdr->keyblock[i].keyMaterialOffset,
|
||||
(unsigned)temp_phdr.keyblock[i].keyMaterialOffset);
|
||||
phdr->keyblock[i].keyMaterialOffset = temp_phdr.keyblock[i].keyMaterialOffset;
|
||||
@@ -432,7 +436,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
}
|
||||
|
||||
if (phdr->keyblock[i].stripes != temp_phdr.keyblock[i].stripes) {
|
||||
log_err(ctx, _("Keyslot %i: stripes repaired (%u -> %u).\n"), i,
|
||||
log_err(ctx, _("Keyslot %i: stripes repaired (%u -> %u)."), i,
|
||||
(unsigned)phdr->keyblock[i].stripes,
|
||||
(unsigned)temp_phdr.keyblock[i].stripes);
|
||||
phdr->keyblock[i].stripes = temp_phdr.keyblock[i].stripes;
|
||||
@@ -441,12 +445,12 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
|
||||
/* Known case - MSDOS partition table signature */
|
||||
if (i == 6 && sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa) {
|
||||
log_err(ctx, _("Keyslot %i: bogus partition signature.\n"), i);
|
||||
log_err(ctx, _("Keyslot %i: bogus partition signature."), i);
|
||||
bad = 1;
|
||||
}
|
||||
|
||||
if(bad) {
|
||||
log_err(ctx, _("Keyslot %i: salt wiped.\n"), i);
|
||||
log_err(ctx, _("Keyslot %i: salt wiped."), i);
|
||||
phdr->keyblock[i].active = LUKS_KEY_DISABLED;
|
||||
memset(&phdr->keyblock[i].passwordSalt, 0x00, LUKS_SALTSIZE);
|
||||
phdr->keyblock[i].passwordIterations = 0;
|
||||
@@ -457,18 +461,18 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
}
|
||||
|
||||
/*
|
||||
* check repair result before writting because repair can't fix out of order
|
||||
* check repair result before writing because repair can't fix out of order
|
||||
* keyslot offsets and would corrupt header again
|
||||
*/
|
||||
if (LUKS_check_keyslots(ctx, phdr))
|
||||
r = -EINVAL;
|
||||
else if (need_write) {
|
||||
log_verbose(ctx, _("Writing LUKS header to disk.\n"));
|
||||
log_verbose(ctx, _("Writing LUKS header to disk."));
|
||||
r = LUKS_write_phdr(phdr, ctx);
|
||||
}
|
||||
out:
|
||||
if (r)
|
||||
log_err(ctx, _("Repair failed.\n"));
|
||||
log_err(ctx, _("Repair failed."));
|
||||
crypt_free_volume_key(vk);
|
||||
crypt_memzero(&temp_phdr, sizeof(temp_phdr));
|
||||
return r;
|
||||
@@ -487,16 +491,16 @@ static int _check_and_convert_hdr(const char *device,
|
||||
if(memcmp(hdr->magic, luksMagic, LUKS_MAGIC_L)) { /* Check magic */
|
||||
log_dbg("LUKS header not detected.");
|
||||
if (require_luks_device)
|
||||
log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device);
|
||||
log_err(ctx, _("Device %s is not a valid LUKS device."), device);
|
||||
return -EINVAL;
|
||||
} else if((hdr->version = ntohs(hdr->version)) != 1) { /* Convert every uint16/32_t item from network byte order */
|
||||
log_err(ctx, _("Unsupported LUKS version %d.\n"), hdr->version);
|
||||
log_err(ctx, _("Unsupported LUKS version %d."), hdr->version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdr->hashSpec[LUKS_HASHSPEC_L - 1] = '\0';
|
||||
if (crypt_hmac_size(hdr->hashSpec) < LUKS_DIGESTSIZE) {
|
||||
log_err(ctx, _("Requested LUKS hash %s is not supported.\n"), hdr->hashSpec);
|
||||
log_err(ctx, _("Requested LUKS hash %s is not supported."), hdr->hashSpec);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -524,7 +528,7 @@ static int _check_and_convert_hdr(const char *device,
|
||||
if (r == -EINVAL)
|
||||
r = _keyslot_repair(hdr, ctx);
|
||||
else
|
||||
log_verbose(ctx, _("No known problems detected for LUKS header.\n"));
|
||||
log_verbose(ctx, _("No known problems detected for LUKS header."));
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -539,7 +543,7 @@ static void _to_lower(char *str, unsigned max_len)
|
||||
|
||||
static void LUKS_fix_header_compatible(struct luks_phdr *header)
|
||||
{
|
||||
/* Old cryptsetup expects "sha1", gcrypt allows case insensistive names,
|
||||
/* Old cryptsetup expects "sha1", gcrypt allows case insensitive names,
|
||||
* so always convert hash to lower case in header */
|
||||
_to_lower(header->hashSpec, LUKS_HASHSPEC_L);
|
||||
|
||||
@@ -564,7 +568,7 @@ int LUKS_read_phdr_backup(const char *backup_file,
|
||||
|
||||
devfd = open(backup_file, O_RDONLY);
|
||||
if (devfd == -1) {
|
||||
log_err(ctx, _("Cannot open header backup file %s.\n"), backup_file);
|
||||
log_err(ctx, _("Cannot open header backup file %s."), backup_file);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -603,7 +607,7 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
|
||||
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
if (devfd < 0) {
|
||||
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(ctx, _("Cannot open device %s."), device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -651,10 +655,10 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
|
||||
devfd = device_open(device, O_RDWR);
|
||||
if (devfd < 0) {
|
||||
if (errno == EACCES)
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied."),
|
||||
device_path(device));
|
||||
else
|
||||
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(ctx, _("Cannot open device %s."), device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -676,14 +680,14 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
|
||||
r = write_blockwise(devfd, device_block_size(device), device_alignment(device),
|
||||
&convHdr, hdr_size) < hdr_size ? -EIO : 0;
|
||||
if (r)
|
||||
log_err(ctx, _("Error during update of LUKS header on device %s.\n"), device_path(device));
|
||||
log_err(ctx, _("Error during update of LUKS header on device %s."), device_path(device));
|
||||
close(devfd);
|
||||
|
||||
/* Re-read header from disk to be sure that in-memory and on-disk data are the same. */
|
||||
if (!r) {
|
||||
r = LUKS_read_phdr(hdr, 1, 0, ctx);
|
||||
if (r)
|
||||
log_err(ctx, _("Error re-reading LUKS header after update on device %s.\n"),
|
||||
log_err(ctx, _("Error re-reading LUKS header after update on device %s."),
|
||||
device_path(device));
|
||||
}
|
||||
|
||||
@@ -691,23 +695,22 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
|
||||
}
|
||||
|
||||
/* Check that kernel supports requested cipher by decryption of one sector */
|
||||
static int LUKS_check_cipher(struct luks_phdr *hdr, struct crypt_device *ctx)
|
||||
int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *cipher, const char *cipher_mode)
|
||||
{
|
||||
int r;
|
||||
struct volume_key *empty_key;
|
||||
char buf[SECTOR_SIZE];
|
||||
|
||||
log_dbg("Checking if cipher %s-%s is usable.", hdr->cipherName, hdr->cipherMode);
|
||||
log_dbg("Checking if cipher %s-%s is usable.", cipher, cipher_mode);
|
||||
|
||||
empty_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
|
||||
empty_key = crypt_alloc_volume_key(keylength, NULL);
|
||||
if (!empty_key)
|
||||
return -ENOMEM;
|
||||
|
||||
/* No need to get KEY quality random but it must avoid known weak keys. */
|
||||
r = crypt_random_get(ctx, empty_key->key, empty_key->keylength, CRYPT_RND_NORMAL);
|
||||
if (!r)
|
||||
r = LUKS_decrypt_from_storage(buf, sizeof(buf), hdr->cipherName,
|
||||
hdr->cipherMode, empty_key, 0, ctx);
|
||||
r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx);
|
||||
|
||||
crypt_free_volume_key(empty_key);
|
||||
crypt_memzero(buf, sizeof(buf));
|
||||
@@ -737,18 +740,18 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
|
||||
if (alignPayload && detached_metadata_device && alignPayload < hdr_sectors) {
|
||||
log_err(ctx, _("Data offset for detached LUKS header must be "
|
||||
"either 0 or higher than header size (%d sectors).\n"),
|
||||
"either 0 or higher than header size (%d sectors)."),
|
||||
hdr_sectors);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (crypt_hmac_size(hashSpec) < LUKS_DIGESTSIZE) {
|
||||
log_err(ctx, _("Requested LUKS hash %s is not supported.\n"), hashSpec);
|
||||
log_err(ctx, _("Requested LUKS hash %s is not supported."), hashSpec);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
|
||||
log_err(ctx, _("Wrong LUKS UUID format provided.\n"));
|
||||
log_err(ctx, _("Wrong LUKS UUID format provided."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!uuid)
|
||||
@@ -767,17 +770,13 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
|
||||
LUKS_fix_header_compatible(header);
|
||||
|
||||
r = LUKS_check_cipher(header, ctx);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_dbg("Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
|
||||
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
|
||||
header->keyBytes);
|
||||
|
||||
r = crypt_random_get(ctx, header->mkDigestSalt, LUKS_SALTSIZE, CRYPT_RND_SALT);
|
||||
if(r < 0) {
|
||||
log_err(ctx, _("Cannot create LUKS header: reading random salt failed.\n"));
|
||||
log_err(ctx, _("Cannot create LUKS header: reading random salt failed."));
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -798,7 +797,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
header->mkDigest,LUKS_DIGESTSIZE,
|
||||
header->mkDigestIterations, 0, 0);
|
||||
if(r < 0) {
|
||||
log_err(ctx, _("Cannot create LUKS header: header digest failed (using hash %s).\n"),
|
||||
log_err(ctx, _("Cannot create LUKS header: header digest failed (using hash %s)."),
|
||||
header->hashSpec);
|
||||
return r;
|
||||
}
|
||||
@@ -838,7 +837,7 @@ int LUKS_hdr_uuid_set(
|
||||
uuid_t partitionUuid;
|
||||
|
||||
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
|
||||
log_err(ctx, _("Wrong LUKS UUID format provided.\n"));
|
||||
log_err(ctx, _("Wrong LUKS UUID format provided."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!uuid)
|
||||
@@ -861,13 +860,13 @@ int LUKS_set_key(unsigned int keyIndex,
|
||||
int r;
|
||||
|
||||
if(hdr->keyblock[keyIndex].active != LUKS_KEY_DISABLED) {
|
||||
log_err(ctx, _("Key slot %d active, purge first.\n"), keyIndex);
|
||||
log_err(ctx, _("Key slot %d active, purge first."), keyIndex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* LUKS keyslot has always at least 4000 stripes accoding to specification */
|
||||
/* LUKS keyslot has always at least 4000 stripes according to specification */
|
||||
if(hdr->keyblock[keyIndex].stripes < 4000) {
|
||||
log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?\n"),
|
||||
log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?"),
|
||||
keyIndex);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1024,9 +1023,6 @@ static int LUKS_open_key(unsigned int keyIndex,
|
||||
/* Allow only empty passphrase with null cipher */
|
||||
if (!r && !strcmp(hdr->cipherName, "cipher_null") && passwordLen)
|
||||
r = -EPERM;
|
||||
|
||||
if (!r)
|
||||
log_verbose(ctx, _("Key slot %d unlocked.\n"), keyIndex);
|
||||
out:
|
||||
crypt_safe_free(AfKey);
|
||||
crypt_free_volume_key(derived_key);
|
||||
@@ -1061,7 +1057,6 @@ int LUKS_open_key_with_hdr(int keyIndex,
|
||||
return r;
|
||||
}
|
||||
/* Warning, early returns above */
|
||||
log_err(ctx, _("No key available with this passphrase.\n"));
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -1079,7 +1074,7 @@ int LUKS_del_key(unsigned int keyIndex,
|
||||
|
||||
r = LUKS_keyslot_set(hdr, keyIndex, 0);
|
||||
if (r) {
|
||||
log_err(ctx, _("Key slot %d is invalid, please select keyslot between 0 and %d.\n"),
|
||||
log_err(ctx, _("Key slot %d is invalid, please select keyslot between 0 and %d."),
|
||||
keyIndex, LUKS_NUMKEYS - 1);
|
||||
return r;
|
||||
}
|
||||
@@ -1093,11 +1088,11 @@ int LUKS_del_key(unsigned int keyIndex,
|
||||
(endOffset - startOffset) * SECTOR_SIZE, NULL, NULL);
|
||||
if (r) {
|
||||
if (r == -EACCES) {
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied."),
|
||||
device_path(device));
|
||||
r = -EINVAL;
|
||||
} else
|
||||
log_err(ctx, _("Cannot wipe device %s.\n"),
|
||||
log_err(ctx, _("Cannot wipe device %s."),
|
||||
device_path(device));
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* LUKS - Linux Unified Key Setup
|
||||
*
|
||||
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -99,6 +99,11 @@ struct luks_phdr {
|
||||
int LUKS_verify_volume_key(const struct luks_phdr *hdr,
|
||||
const struct volume_key *vk);
|
||||
|
||||
int LUKS_check_cipher(struct crypt_device *ctx,
|
||||
size_t keylength,
|
||||
const char *cipher,
|
||||
const char *cipher_mode);
|
||||
|
||||
int LUKS_generate_phdr(
|
||||
struct luks_phdr *header,
|
||||
const struct volume_key *vk,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -22,7 +22,7 @@
|
||||
#ifndef _CRYPTSETUP_LUKS2_ONDISK_H
|
||||
#define _CRYPTSETUP_LUKS2_ONDISK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
|
||||
#define LUKS2_MAGIC_2ND "SKUL\xba\xbe"
|
||||
@@ -43,12 +43,12 @@
|
||||
|
||||
#define LUKS2_DIGEST_MAX 8
|
||||
|
||||
typedef int digests_t[LUKS2_DIGEST_MAX];
|
||||
|
||||
#define CRYPT_ANY_SEGMENT -1
|
||||
#define CRYPT_DEFAULT_SEGMENT 0
|
||||
#define CRYPT_DEFAULT_SEGMENT_STR "0"
|
||||
|
||||
#define CRYPT_ANY_DIGEST -1
|
||||
|
||||
/*
|
||||
* LUKS2 header on-disk.
|
||||
*
|
||||
@@ -97,6 +97,25 @@ struct luks2_hdr {
|
||||
json_object *jobj;
|
||||
};
|
||||
|
||||
struct luks2_keyslot_params {
|
||||
enum { LUKS2_KEYSLOT_AF_LUKS1 = 0 } af_type;
|
||||
enum { LUKS2_KEYSLOT_AREA_RAW = 0 } area_type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
|
||||
unsigned int stripes;
|
||||
} luks1;
|
||||
} af;
|
||||
|
||||
union {
|
||||
struct {
|
||||
char encryption[65]; // or include utils_crypt.h
|
||||
size_t key_size;
|
||||
} raw;
|
||||
} area;
|
||||
};
|
||||
|
||||
/*
|
||||
* Supportable header sizes (hdr_disk + JSON area)
|
||||
* Also used as offset for the 2nd header.
|
||||
@@ -109,10 +128,14 @@ struct luks2_hdr {
|
||||
|
||||
#define LUKS2_MAX_KEYSLOTS_SIZE 0x8000000 /* 128 MiB */
|
||||
|
||||
/* Offsets for secondary header (for scan if primary header is corrupted). */
|
||||
#define LUKS2_HDR2_OFFSETS { 0x04000, 0x008000, 0x010000, 0x020000, \
|
||||
0x40000, 0x080000, 0x100000, 0x200000, 0x400000 }
|
||||
|
||||
int LUKS2_hdr_version_unlocked(struct crypt_device *cd,
|
||||
const char *backup_file);
|
||||
|
||||
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair);
|
||||
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
|
||||
@@ -138,6 +161,8 @@ int LUKS2_hdr_restore(struct crypt_device *cd,
|
||||
uint64_t LUKS2_hdr_and_areas_size(json_object *jobj);
|
||||
uint64_t LUKS2_keyslots_size(json_object *jobj);
|
||||
|
||||
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd);
|
||||
|
||||
/*
|
||||
* Generic LUKS2 keyslot
|
||||
*/
|
||||
@@ -153,7 +178,8 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
const struct volume_key *vk);
|
||||
const struct volume_key *vk,
|
||||
const struct luks2_keyslot_params *params);
|
||||
|
||||
int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
@@ -188,6 +214,11 @@ int LUKS2_token_assign(struct crypt_device *cd,
|
||||
int assign,
|
||||
int commit);
|
||||
|
||||
int LUKS2_token_is_assigned(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int token);
|
||||
|
||||
int LUKS2_token_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int token,
|
||||
@@ -224,14 +255,19 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
|
||||
const char *name,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_tokens_count(struct luks2_hdr *hdr);
|
||||
|
||||
/*
|
||||
* Generic LUKS2 digest
|
||||
*/
|
||||
int LUKS2_digests_verify_by_segment(struct crypt_device *cd,
|
||||
int LUKS2_digest_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment);
|
||||
|
||||
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const struct volume_key *vk,
|
||||
digests_t digests);
|
||||
const struct volume_key *vk);
|
||||
|
||||
void LUKS2_digests_erase_unused(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr);
|
||||
@@ -244,23 +280,6 @@ int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
int LUKS2_digest_dump(struct crypt_device *cd,
|
||||
int digest);
|
||||
|
||||
int LUKS2_digest_json_get(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest,
|
||||
const char **json);
|
||||
|
||||
int LUKS2_digest_json_set(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest,
|
||||
const char *json);
|
||||
|
||||
int LUKS2_digests_assign(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
digests_t digests,
|
||||
int assign,
|
||||
int commit);
|
||||
|
||||
int LUKS2_digest_assign(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -275,10 +294,9 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd,
|
||||
int assign,
|
||||
int commit);
|
||||
|
||||
int LUKS2_digests_by_keyslot(struct crypt_device *cd,
|
||||
int LUKS2_digest_by_keyslot(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
digests_t digests);
|
||||
int keyslot);
|
||||
|
||||
int LUKS2_digest_create(struct crypt_device *cd,
|
||||
const char *type,
|
||||
@@ -316,6 +334,10 @@ uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr);
|
||||
int LUKS2_get_sector_size(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
|
||||
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
|
||||
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
size_t key_size, struct luks2_keyslot_params *params);
|
||||
int LUKS2_get_keyslot_params(struct luks2_hdr *hdr, int keyslot,
|
||||
struct luks2_keyslot_params *params);
|
||||
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment);
|
||||
int LUKS2_get_keyslot_key_size(struct luks2_hdr *hdr, int keyslot);
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type);
|
||||
@@ -340,8 +362,10 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
|
||||
|
||||
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
|
||||
|
||||
int crypt_use_keyring_for_vk(const struct crypt_device *cd);
|
||||
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
|
||||
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);
|
||||
|
||||
struct luks_phdr;
|
||||
int LUKS2_luks1_to_luks2(struct crypt_device *cd,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, digest handling
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -28,22 +28,6 @@ static const digest_handler *digest_handlers[LUKS2_DIGEST_MAX] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
int crypt_digest_register(const digest_handler *handler)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LUKS2_DIGEST_MAX && digest_handlers[i]; i++) {
|
||||
if (!strcmp(digest_handlers[i]->name, handler->name))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (i == LUKS2_DIGEST_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
digest_handlers[i] = handler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type)
|
||||
{
|
||||
int i;
|
||||
@@ -107,13 +91,11 @@ int LUKS2_digest_create(struct crypt_device *cd,
|
||||
return dh->store(cd, digest, vk->key, vk->keylength) ?: digest;
|
||||
}
|
||||
|
||||
int LUKS2_digests_by_keyslot(struct crypt_device *cd,
|
||||
int LUKS2_digest_by_keyslot(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
digests_t digests)
|
||||
int keyslot)
|
||||
{
|
||||
char keyslot_name[16];
|
||||
int i = 0;
|
||||
json_object *jobj_digests, *jobj_digest_keyslots;
|
||||
|
||||
if (snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
|
||||
@@ -124,13 +106,10 @@ int LUKS2_digests_by_keyslot(struct crypt_device *cd,
|
||||
json_object_object_foreach(jobj_digests, key, val) {
|
||||
json_object_object_get_ex(val, "keyslots", &jobj_digest_keyslots);
|
||||
if (LUKS2_array_jobj(jobj_digest_keyslots, keyslot_name))
|
||||
digests[i++] = atoi(key);
|
||||
return atoi(key);
|
||||
}
|
||||
|
||||
if (i < LUKS2_DIGEST_MAX)
|
||||
digests[i] = -1;
|
||||
|
||||
return i ? 0 : -ENOENT;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
@@ -139,31 +118,24 @@ int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
int keyslot)
|
||||
{
|
||||
const digest_handler *h;
|
||||
digests_t digests;
|
||||
int i, r;
|
||||
int digest, r;
|
||||
|
||||
r = LUKS2_digests_by_keyslot(cd, hdr, keyslot, digests);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
digest = LUKS2_digest_by_keyslot(cd, hdr, keyslot);
|
||||
if (digest < 0)
|
||||
return digest;
|
||||
|
||||
log_dbg("Verifying key from keyslot %d, digest %d.", keyslot, digest);
|
||||
h = LUKS2_digest_handler(cd, digest);
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = h->verify(cd, digest, vk->key, vk->keylength);
|
||||
if (r < 0) {
|
||||
log_dbg("Digest %d (%s) verify failed with %d.", digest, h->name, r);
|
||||
return r;
|
||||
|
||||
for (i = 0; i < LUKS2_DIGEST_MAX && digests[i] != -1 ; i++) {
|
||||
log_dbg("Verifying key from keyslot %d, digest %d.",
|
||||
keyslot, digests[i]);
|
||||
h = LUKS2_digest_handler(cd, digests[i]);
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = h->verify(cd, digests[i], vk->key, vk->keylength);
|
||||
if (r < 0) {
|
||||
log_dbg("Digest %d (%s) verify failed with %d.",
|
||||
digests[i], h->name, r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return digest;
|
||||
}
|
||||
|
||||
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
|
||||
@@ -176,16 +148,40 @@ int LUKS2_digest_dump(struct crypt_device *cd, int digest)
|
||||
return h->dump(cd, digest);
|
||||
}
|
||||
|
||||
int LUKS2_digests_verify_by_segment(struct crypt_device *cd,
|
||||
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const struct volume_key *vk,
|
||||
digests_t digests)
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
const digest_handler *h;
|
||||
int digest, r;
|
||||
|
||||
digest = LUKS2_digest_by_segment(cd, hdr, segment);
|
||||
if (digest < 0)
|
||||
return digest;
|
||||
|
||||
log_dbg("Verifying key digest %d.", digest);
|
||||
|
||||
h = LUKS2_digest_handler(cd, digest);
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = h->verify(cd, digest, vk->key, vk->keylength);
|
||||
if (r < 0) {
|
||||
log_dbg("Digest %d (%s) verify failed with %d.", digest, h->name, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
return digest;
|
||||
}
|
||||
|
||||
/* FIXME: segment can have more digests */
|
||||
int LUKS2_digest_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment)
|
||||
{
|
||||
char segment_name[16];
|
||||
const digest_handler *h;
|
||||
json_object *jobj_digests, *jobj_digest_segments;
|
||||
int digest, r, i = 0;
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
|
||||
|
||||
@@ -197,41 +193,10 @@ int LUKS2_digests_verify_by_segment(struct crypt_device *cd,
|
||||
if (!LUKS2_array_jobj(jobj_digest_segments, segment_name))
|
||||
continue;
|
||||
|
||||
digest = atoi(key);
|
||||
log_dbg("Verifying key digest %d.", digest);
|
||||
|
||||
h = LUKS2_digest_handler(cd, digest);
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = h->verify(cd, digest, vk->key, vk->keylength);
|
||||
if (r < 0) {
|
||||
log_dbg("Digest %d (%s) verify failed with %d.", digest, h->name, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (digests)
|
||||
digests[i] = digest;
|
||||
i++;
|
||||
return atoi(key);
|
||||
}
|
||||
|
||||
if (digests && i < LUKS2_DIGEST_MAX)
|
||||
digests[i] = -1;
|
||||
|
||||
return i ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_digest_json_get(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int digest, const char **json)
|
||||
{
|
||||
json_object *jobj_digest;
|
||||
|
||||
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
|
||||
if (!jobj_digest)
|
||||
return -EINVAL;
|
||||
|
||||
*json = json_object_to_json_string_ext(jobj_digest, JSON_C_TO_STRING_PLAIN);
|
||||
return 0;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
@@ -264,20 +229,6 @@ static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_digests_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int keyslot, digests_t digests, int assign, int commit)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < LUKS2_DIGEST_MAX && digests[i] != -1; i++) {
|
||||
r = LUKS2_digest_assign(cd, hdr, keyslot, digests[i], assign, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
|
||||
}
|
||||
|
||||
int LUKS2_digest_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int keyslot, int digest, int assign, int commit)
|
||||
{
|
||||
@@ -363,14 +314,14 @@ static int digest_unused(json_object *jobj_digest)
|
||||
json_object *jobj;
|
||||
|
||||
json_object_object_get_ex(jobj_digest, "segments", &jobj);
|
||||
if (!jobj || !json_object_is_type(jobj, json_type_array) || json_object_array_length(jobj))
|
||||
if (!jobj || !json_object_is_type(jobj, json_type_array) || json_object_array_length(jobj) > 0)
|
||||
return 0;
|
||||
|
||||
json_object_object_get_ex(jobj_digest, "keyslots", &jobj);
|
||||
if (!jobj || !json_object_is_type(jobj, json_type_array))
|
||||
return 0;
|
||||
|
||||
return json_object_array_length(jobj) ? 0 : 1;
|
||||
return json_object_array_length(jobj) > 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
void LUKS2_digests_erase_unused(struct crypt_device *cd,
|
||||
@@ -389,3 +340,58 @@ void LUKS2_digests_erase_unused(struct crypt_device *cd,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Key description helpers */
|
||||
static char *get_key_description_by_digest(struct crypt_device *cd, int digest)
|
||||
{
|
||||
char *desc, digest_str[3];
|
||||
int r;
|
||||
size_t len;
|
||||
|
||||
if (!crypt_get_uuid(cd))
|
||||
return NULL;
|
||||
|
||||
r = snprintf(digest_str, sizeof(digest_str), "d%u", digest);
|
||||
if (r < 0 || (size_t)r >= sizeof(digest_str))
|
||||
return NULL;
|
||||
|
||||
/* "cryptsetup:<uuid>-<digest_str>" + \0 */
|
||||
len = strlen(crypt_get_uuid(cd)) + strlen(digest_str) + 13;
|
||||
|
||||
desc = malloc(len);
|
||||
if (!desc)
|
||||
return NULL;
|
||||
|
||||
r = snprintf(desc, len, "%s:%s-%s", "cryptsetup", crypt_get_uuid(cd), digest_str);
|
||||
if (r < 0 || (size_t)r >= len) {
|
||||
free(desc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
int LUKS2_key_description_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int segment)
|
||||
{
|
||||
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_segment(cd, hdr, segment));
|
||||
int r;
|
||||
|
||||
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(cd, 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;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -95,9 +95,10 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
{
|
||||
json_object *jobj_digest, *jobj_digests;
|
||||
char salt[LUKS_SALTSIZE], digest_raw[128], num[16];
|
||||
int r;
|
||||
int hmac_size, r;
|
||||
char *base64_str;
|
||||
struct luks2_hdr *hdr;
|
||||
struct crypt_pbkdf_limits pbkdf_limits;
|
||||
struct crypt_pbkdf_type pbkdf = {
|
||||
.type = CRYPT_KDF_PBKDF2,
|
||||
.hash = "sha256",
|
||||
@@ -110,16 +111,24 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = crypt_pbkdf_get_limits(CRYPT_KDF_PBKDF2, &pbkdf_limits);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (crypt_get_pbkdf(cd)->flags & CRYPT_PBKDF_NO_BENCHMARK)
|
||||
pbkdf.iterations = MIN_PBKDF2_ITERATIONS;
|
||||
pbkdf.iterations = pbkdf_limits.min_iterations;
|
||||
else {
|
||||
r = crypt_benchmark_pbkdf_internal(cd, &pbkdf, volume_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
hmac_size = crypt_hmac_size(pbkdf.hash);
|
||||
if (hmac_size < 0)
|
||||
return hmac_size;
|
||||
|
||||
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, pbkdf.hash, volume_key, volume_key_len,
|
||||
salt, LUKS_SALTSIZE, digest_raw, crypt_hmac_size(pbkdf.hash),
|
||||
salt, LUKS_SALTSIZE, digest_raw, hmac_size,
|
||||
pbkdf.iterations, 0, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -146,7 +155,7 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
json_object_object_add(jobj_digest, "salt", json_object_new_string(base64_str));
|
||||
free(base64_str);
|
||||
|
||||
base64_encode_alloc(digest_raw, crypt_hmac_size(pbkdf.hash), &base64_str);
|
||||
base64_encode_alloc(digest_raw, hmac_size, &base64_str);
|
||||
if (!base64_str) {
|
||||
json_object_put(jobj_digest);
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -74,9 +74,10 @@ static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_di
|
||||
const char *json_area, size_t json_len)
|
||||
{
|
||||
struct crypt_hash *hd = NULL;
|
||||
int r;
|
||||
int hash_size, r;
|
||||
|
||||
if (crypt_hash_size(alg) <= 0 || crypt_hash_init(&hd, alg))
|
||||
hash_size = crypt_hash_size(alg);
|
||||
if (hash_size <= 0 || crypt_hash_init(&hd, alg))
|
||||
return -EINVAL;
|
||||
|
||||
/* Binary header, csum zeroed. */
|
||||
@@ -87,7 +88,7 @@ static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_di
|
||||
r = crypt_hash_write(hd, json_area, json_len);
|
||||
|
||||
if (!r)
|
||||
r = crypt_hash_final(hd, (char*)hdr_disk->csum, crypt_hash_size(alg));
|
||||
r = crypt_hash_final(hd, (char*)hdr_disk->csum, (size_t)hash_size);
|
||||
|
||||
crypt_hash_destroy(hd);
|
||||
return r;
|
||||
@@ -100,9 +101,10 @@ static int hdr_checksum_check(const char *alg, struct luks2_hdr_disk *hdr_disk,
|
||||
const char *json_area, size_t json_len)
|
||||
{
|
||||
struct luks2_hdr_disk hdr_tmp;
|
||||
int r;
|
||||
int hash_size, r;
|
||||
|
||||
if (crypt_hash_size(alg) <= 0)
|
||||
hash_size = crypt_hash_size(alg);
|
||||
if (hash_size <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Copy header and zero checksum. */
|
||||
@@ -116,7 +118,7 @@ static int hdr_checksum_check(const char *alg, struct luks2_hdr_disk *hdr_disk,
|
||||
log_dbg_checksum(hdr_disk->csum, alg, "on-disk");
|
||||
log_dbg_checksum(hdr_tmp.csum, alg, "in-memory");
|
||||
|
||||
if (memcmp(hdr_tmp.csum, hdr_disk->csum, crypt_hash_size(alg)))
|
||||
if (memcmp(hdr_tmp.csum, hdr_disk->csum, (size_t)hash_size))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -182,7 +184,7 @@ static void hdr_to_disk(struct luks2_hdr *hdr,
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity checks before checkum is validated
|
||||
* Sanity checks before checksum is validated
|
||||
*/
|
||||
static int hdr_disk_sanity_check_pre(struct luks2_hdr_disk *hdr,
|
||||
size_t *hdr_json_size, int secondary,
|
||||
@@ -221,7 +223,7 @@ static int hdr_read_disk(struct device *device, struct luks2_hdr_disk *hdr_disk,
|
||||
size_t hdr_json_size = 0;
|
||||
int devfd = -1, r;
|
||||
|
||||
log_dbg("Trying to read %s LUKS2 header at offset %" PRIu64 ".",
|
||||
log_dbg("Trying to read %s LUKS2 header at offset 0x%" PRIx64 ".",
|
||||
secondary ? "secondary" : "primary", offset);
|
||||
|
||||
devfd = device_open_locked(device, O_RDONLY);
|
||||
@@ -324,7 +326,7 @@ static int hdr_write_disk(struct device *device, struct luks2_hdr *hdr,
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate checksum and write header with checkum.
|
||||
* Calculate checksum and write header with checksum.
|
||||
*/
|
||||
r = hdr_checksum_calculate(hdr_disk.checksum_alg, &hdr_disk,
|
||||
json_area, hdr_json_len);
|
||||
@@ -361,7 +363,7 @@ static int LUKS2_check_device_size(struct crypt_device *cd, struct device *devic
|
||||
if (falloc && !device_fallocate(device, hdr_size))
|
||||
return 0;
|
||||
|
||||
log_err(cd, _("Device %s is too small. (LUKS2 requires at least %" PRIu64 " bytes.)\n"),
|
||||
log_err(cd, _("Device %s is too small. (LUKS2 requires at least %" PRIu64 " bytes.)"),
|
||||
device_path(device), hdr_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -406,7 +408,8 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
|
||||
/*
|
||||
* Generate text space-efficient JSON representation to json area.
|
||||
*/
|
||||
json_text = json_object_to_json_string_ext(hdr->jobj, JSON_C_TO_STRING_PLAIN);
|
||||
json_text = json_object_to_json_string_ext(hdr->jobj,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
|
||||
if (!json_text || !*json_text) {
|
||||
log_dbg("Cannot parse JSON object to text representation.");
|
||||
free(json_area);
|
||||
@@ -424,7 +427,7 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
|
||||
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write device lock.\n"));
|
||||
log_err(cd, _("Failed to acquire write device lock."));
|
||||
free(json_area);
|
||||
return r;
|
||||
}
|
||||
@@ -490,6 +493,15 @@ static int validate_luks2_json_object(json_object *jobj_hdr)
|
||||
}
|
||||
|
||||
r = LUKS2_hdr_validate(jobj_hdr);
|
||||
if (r) {
|
||||
log_dbg("Repairing JSON metadata.");
|
||||
/* try to correct known glitches */
|
||||
LUKS2_hdr_repair(jobj_hdr);
|
||||
|
||||
/* run validation again */
|
||||
r = LUKS2_hdr_validate(jobj_hdr);
|
||||
}
|
||||
|
||||
if (r)
|
||||
log_dbg("ERROR: LUKS2 validation failed");
|
||||
|
||||
@@ -504,7 +516,7 @@ static json_object *parse_and_validate_json(const char *json_area, int length)
|
||||
if (!jobj)
|
||||
return NULL;
|
||||
|
||||
/* successfull parse_json_len must not return offset <= 0 */
|
||||
/* successful parse_json_len must not return offset <= 0 */
|
||||
assert(offset > 0);
|
||||
|
||||
r = validate_json_area(json_area, offset, length);
|
||||
@@ -519,21 +531,71 @@ static json_object *parse_and_validate_json(const char *json_area, int length)
|
||||
return jobj;
|
||||
}
|
||||
|
||||
static int detect_device_signatures(const char *path)
|
||||
{
|
||||
blk_probe_status prb_state;
|
||||
int r;
|
||||
struct blkid_handle *h;
|
||||
|
||||
if (!blk_supported()) {
|
||||
log_dbg("Blkid probing of device signatures disabled.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r = blk_init_by_path(&h, path))) {
|
||||
log_dbg("Failed to initialize blkid_handle by path.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* We don't care about details. Be fast. */
|
||||
blk_set_chains_for_fast_detection(h);
|
||||
|
||||
/* Filter out crypto_LUKS. we don't care now */
|
||||
blk_superblocks_filter_luks(h);
|
||||
|
||||
prb_state = blk_safeprobe(h);
|
||||
|
||||
switch (prb_state) {
|
||||
case PRB_AMBIGUOUS:
|
||||
log_dbg("Blkid probe couldn't decide device type unambiguously.");
|
||||
/* fall through */
|
||||
case PRB_FAIL:
|
||||
log_dbg("Blkid probe failed.");
|
||||
r = -EINVAL;
|
||||
break;
|
||||
case PRB_OK: /* crypto_LUKS type is filtered out */
|
||||
r = -EINVAL;
|
||||
|
||||
if (blk_is_partition(h))
|
||||
log_dbg("Blkid probe detected partition type '%s'", blk_get_partition_type(h));
|
||||
else if (blk_is_superblock(h))
|
||||
log_dbg("blkid probe detected superblock type '%s'", blk_get_superblock_type(h));
|
||||
break;
|
||||
case PRB_EMPTY:
|
||||
log_dbg("Blkid probe detected no foreign device signature.");
|
||||
}
|
||||
blk_free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and convert on-disk LUKS2 header to in-memory representation..
|
||||
* Try to do recovery if on-disk state is not consistent.
|
||||
*/
|
||||
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct device *device, int do_recovery)
|
||||
struct device *device, int do_recovery, int do_blkprobe)
|
||||
{
|
||||
enum { HDR_OK, HDR_OBSOLETE, HDR_FAIL, HDR_FAIL_IO } state_hdr1, state_hdr2;
|
||||
struct luks2_hdr_disk hdr_disk1, hdr_disk2;
|
||||
char *json_area1 = NULL, *json_area2 = NULL;
|
||||
json_object *jobj_hdr1 = NULL, *jobj_hdr2 = NULL;
|
||||
int i, r;
|
||||
unsigned int i;
|
||||
int r;
|
||||
uint64_t hdr_size;
|
||||
uint64_t hdr2_offsets[] = LUKS2_HDR2_OFFSETS;
|
||||
|
||||
if (do_recovery && !crypt_metadata_locking_enabled()) {
|
||||
/* Skip auto-recovery if locks are disabled and we're not doing LUKS2 explicit repair */
|
||||
if (do_recovery && do_blkprobe && !crypt_metadata_locking_enabled()) {
|
||||
do_recovery = 0;
|
||||
log_dbg("Disabling header auto-recovery due to locking being disabled.");
|
||||
}
|
||||
@@ -564,8 +626,8 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
/*
|
||||
* No header size, check all known offsets.
|
||||
*/
|
||||
for (r = -EINVAL,i = 2; r < 0 && i <= 1024; i <<= 1)
|
||||
r = hdr_read_disk(device, &hdr_disk2, &json_area2, i * 4096, 1);
|
||||
for (r = -EINVAL,i = 0; r < 0 && i < ARRAY_SIZE(hdr2_offsets); i++)
|
||||
r = hdr_read_disk(device, &hdr_disk2, &json_area2, hdr2_offsets[i], 1);
|
||||
|
||||
if (r == 0) {
|
||||
jobj_hdr2 = parse_and_validate_json(json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
|
||||
@@ -604,6 +666,12 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
if (state_hdr1 == HDR_OK && state_hdr2 != HDR_OK) {
|
||||
log_dbg("Secondary LUKS2 header requires recovery.");
|
||||
|
||||
if (do_blkprobe && (r = detect_device_signatures(device_path(device)))) {
|
||||
log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n"
|
||||
"Please run \"cryptsetup repair\" for recovery."));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (do_recovery) {
|
||||
memcpy(&hdr_disk2, &hdr_disk1, LUKS2_HDR_BIN_LEN);
|
||||
r = crypt_random_get(NULL, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT);
|
||||
@@ -619,6 +687,12 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
} else if (state_hdr1 != HDR_OK && state_hdr2 == HDR_OK) {
|
||||
log_dbg("Primary LUKS2 header requires recovery.");
|
||||
|
||||
if (do_blkprobe && (r = detect_device_signatures(device_path(device)))) {
|
||||
log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n"
|
||||
"Please run \"cryptsetup repair\" for recovery."));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (do_recovery) {
|
||||
memcpy(&hdr_disk1, &hdr_disk2, LUKS2_HDR_BIN_LEN);
|
||||
r = crypt_random_get(NULL, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -33,11 +33,16 @@
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
/* override useless forward slash escape when supported by json-c */
|
||||
#ifndef JSON_C_TO_STRING_NOSLASHESCAPE
|
||||
#define JSON_C_TO_STRING_NOSLASHESCAPE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On-disk access function prototypes
|
||||
*/
|
||||
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct device *device, int do_recovery);
|
||||
struct device *device, int do_recovery, int do_blkprobe);
|
||||
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct device *device);
|
||||
|
||||
@@ -46,8 +51,9 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
*/
|
||||
json_object *LUKS2_get_keyslot_jobj(struct luks2_hdr *hdr, int keyslot);
|
||||
json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token);
|
||||
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int keyslot);
|
||||
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int digest);
|
||||
json_object *LUKS2_get_segment_jobj(struct luks2_hdr *hdr, int segment);
|
||||
json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr);
|
||||
|
||||
void hexprint_base64(struct crypt_device *cd, json_object *jobj,
|
||||
const char *sep, const char *line_sep);
|
||||
@@ -55,6 +61,7 @@ void hexprint_base64(struct crypt_device *cd, json_object *jobj,
|
||||
json_object *parse_json_len(const char *json_area, int length, int *end_offset);
|
||||
uint64_t json_object_get_uint64(json_object *jobj);
|
||||
uint32_t json_object_get_uint32(json_object *jobj);
|
||||
json_object *json_object_new_uint64(uint64_t value);
|
||||
|
||||
void JSON_DBG(json_object *jobj, const char *desc);
|
||||
|
||||
@@ -62,12 +69,22 @@ void JSON_DBG(json_object *jobj, const char *desc);
|
||||
* LUKS2 JSON validation
|
||||
*/
|
||||
|
||||
/* validation helper */
|
||||
json_object *json_contains(json_object *jobj, const char *name, const char *section,
|
||||
const char *key, json_type type);
|
||||
|
||||
int LUKS2_hdr_validate(json_object *hdr_jobj);
|
||||
int LUKS2_keyslot_validate(json_object *hdr_jobj, json_object *hdr_keyslot, const char *key);
|
||||
int LUKS2_check_json_size(const struct luks2_hdr *hdr);
|
||||
int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const char *key);
|
||||
void LUKS2_token_dump(struct crypt_device *cd, int token);
|
||||
|
||||
/*
|
||||
* LUKS2 JSON repair for known glitches
|
||||
*/
|
||||
void LUKS2_hdr_repair(json_object *jobj_hdr);
|
||||
void LUKS2_keyslots_repair(json_object *jobj_hdr);
|
||||
|
||||
/*
|
||||
* JSON array helpers
|
||||
*/
|
||||
@@ -82,7 +99,10 @@ struct json_object *LUKS2_array_remove(struct json_object *array, const char *nu
|
||||
* LUKS2 keyslots handlers (EXPERIMENTAL)
|
||||
*/
|
||||
typedef int (*keyslot_alloc_func)(struct crypt_device *cd, int keyslot,
|
||||
size_t volume_key_len);
|
||||
size_t volume_key_len,
|
||||
const struct luks2_keyslot_params *params);
|
||||
typedef int (*keyslot_update_func)(struct crypt_device *cd, int keyslot,
|
||||
const struct luks2_keyslot_params *params);
|
||||
typedef int (*keyslot_open_func) (struct crypt_device *cd, int keyslot,
|
||||
const char *password, size_t password_len,
|
||||
char *volume_key, size_t volume_key_len);
|
||||
@@ -91,20 +111,29 @@ typedef int (*keyslot_store_func)(struct crypt_device *cd, int keyslot,
|
||||
const char *volume_key, size_t volume_key_len);
|
||||
typedef int (*keyslot_wipe_func) (struct crypt_device *cd, int keyslot);
|
||||
typedef int (*keyslot_dump_func) (struct crypt_device *cd, int keyslot);
|
||||
typedef int (*keyslot_validate_func) (struct crypt_device *cd, int keyslot);
|
||||
typedef int (*keyslot_validate_func) (struct crypt_device *cd, json_object *jobj_keyslot);
|
||||
typedef void(*keyslot_repair_func) (struct crypt_device *cd, json_object *jobj_keyslot);
|
||||
|
||||
int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
/* see LUKS2_luks2_to_luks1 */
|
||||
int placeholder_keyslot_alloc(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
uint64_t area_offset,
|
||||
uint64_t area_length,
|
||||
size_t volume_key_len);
|
||||
|
||||
/* validate all keyslot implementations in hdr json */
|
||||
int LUKS2_keyslots_validate(json_object *hdr_jobj);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
keyslot_alloc_func alloc;
|
||||
keyslot_update_func update;
|
||||
keyslot_open_func open;
|
||||
keyslot_store_func store;
|
||||
keyslot_wipe_func wipe;
|
||||
keyslot_dump_func dump;
|
||||
keyslot_validate_func validate;
|
||||
keyslot_repair_func repair;
|
||||
} keyslot_handler;
|
||||
|
||||
/**
|
||||
@@ -123,13 +152,8 @@ typedef struct {
|
||||
digest_dump_func dump;
|
||||
} digest_handler;
|
||||
|
||||
int crypt_digest_register(const digest_handler *handler);
|
||||
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type);
|
||||
|
||||
#define CRYPT_ANY_DIGEST -1
|
||||
int crypt_keyslot_assign_digest(struct crypt_device *cd, int keyslot, int digest);
|
||||
int crypt_keyslot_unassign_digest(struct crypt_device *cd, int keyslot, int digest);
|
||||
|
||||
/**
|
||||
* LUKS2 token handlers (internal use only)
|
||||
*/
|
||||
@@ -147,7 +171,6 @@ typedef struct {
|
||||
int token_keyring_set(json_object **, const void *);
|
||||
int token_keyring_get(json_object *, void *);
|
||||
|
||||
#define CRYPT_ANY_TOKEN -1
|
||||
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
size_t keylength, uint64_t *area_offset, uint64_t *area_length);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -96,7 +96,7 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
}
|
||||
|
||||
if (get_max_offset(cd) && (offset + length) > get_max_offset(cd)) {
|
||||
log_err(cd, _("No space for new keyslot.\n"));
|
||||
log_err(cd, _("No space for new keyslot."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ int LUKS2_generate_hdr(
|
||||
crypt_random_get(NULL, (char*)hdr->salt2, LUKS2_SALT_L, CRYPT_RND_SALT);
|
||||
|
||||
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
|
||||
log_err(cd, _("Wrong LUKS UUID format provided.\n"));
|
||||
log_err(cd, _("Wrong LUKS UUID format provided."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!uuid)
|
||||
@@ -186,11 +186,11 @@ int LUKS2_generate_hdr(
|
||||
else {
|
||||
//FIXME
|
||||
//offset = size_round_up(areas[7].offset + areas[7].length, alignPayload * SECTOR_SIZE);
|
||||
offset = size_round_up(LUKS2_HDR_DEFAULT_LEN, alignPayload * sector_size);
|
||||
offset = size_round_up(LUKS2_HDR_DEFAULT_LEN, (size_t)alignPayload * sector_size);
|
||||
offset += alignOffset;
|
||||
}
|
||||
|
||||
json_object_object_add(jobj_segment, "offset", json_object_new_string(uint64_to_str(num, sizeof(num), &offset)));
|
||||
json_object_object_add(jobj_segment, "offset", json_object_new_uint64(offset));
|
||||
json_object_object_add(jobj_segment, "iv_tweak", json_object_new_string("0"));
|
||||
json_object_object_add(jobj_segment, "size", json_object_new_string("dynamic"));
|
||||
json_object_object_add(jobj_segment, "encryption", json_object_new_string(cipher));
|
||||
@@ -208,12 +208,11 @@ int LUKS2_generate_hdr(
|
||||
json_object_object_add(jobj_segments, num, jobj_segment);
|
||||
|
||||
json_size = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
|
||||
json_object_object_add(jobj_config, "json_size",
|
||||
json_object_new_string(uint64_to_str(num, sizeof(num), &json_size)));
|
||||
json_object_object_add(jobj_config, "json_size", json_object_new_uint64(json_size));
|
||||
|
||||
/* for detached metadata device compute reasonable keyslot areas size */
|
||||
// FIXME: this is coupled with FIXME above
|
||||
if (detached_metadata_device)
|
||||
if (detached_metadata_device && !offset)
|
||||
keyslots_size = LUKS2_HDR_DEFAULT_LEN - get_min_offset(hdr);
|
||||
else
|
||||
keyslots_size = offset - get_min_offset(hdr);
|
||||
@@ -225,8 +224,7 @@ int LUKS2_generate_hdr(
|
||||
/* keyslots size has to be 4 KiB aligned */
|
||||
keyslots_size -= (keyslots_size % 4096);
|
||||
|
||||
json_object_object_add(jobj_config, "keyslots_size",
|
||||
json_object_new_string(uint64_to_str(num, sizeof(num), &keyslots_size)));
|
||||
json_object_object_add(jobj_config, "keyslots_size", json_object_new_uint64(keyslots_size));
|
||||
|
||||
JSON_DBG(hdr->jobj, "Header JSON");
|
||||
return 0;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, keyslot handling
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -63,14 +63,6 @@ static const keyslot_handler
|
||||
return LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj2));
|
||||
}
|
||||
|
||||
static crypt_keyslot_info LUKS2_keyslot_active(struct luks2_hdr *hdr, int keyslot)
|
||||
{
|
||||
if (keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return CRYPT_SLOT_INVALID;
|
||||
|
||||
return LUKS2_get_keyslot_jobj(hdr, keyslot) ? CRYPT_SLOT_ACTIVE : CRYPT_SLOT_INACTIVE;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
|
||||
{
|
||||
int i;
|
||||
@@ -82,77 +74,27 @@ int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int digests_by_segment(json_object *jobj_digests, const char *segment,
|
||||
digests_t digests)
|
||||
{
|
||||
json_object *jobj_segs;
|
||||
int i = 0;
|
||||
|
||||
json_object_object_foreach(jobj_digests, dig, val) {
|
||||
json_object_object_get_ex(val, "segments", &jobj_segs);
|
||||
if (LUKS2_array_jobj(jobj_segs, segment))
|
||||
digests[i++] = atoi(dig);
|
||||
}
|
||||
|
||||
if (i < LUKS2_DIGEST_MAX)
|
||||
digests[i] = -1;
|
||||
|
||||
return i ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
static int is_in(const int super[], int super_size, int elem)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < super_size && super[i] != -1; i++)
|
||||
if (super[i] == elem)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_subset(const int super[], const int sub[], int super_size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < super_size && sub[i] != -1; i++)
|
||||
if (!is_in(super, super_size, sub[i]))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check if a keyslot is asssigned to specific segment */
|
||||
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
{
|
||||
char keyslot_name[16], segment_name[16];
|
||||
digests_t keyslot_digests, segment_digests;
|
||||
json_object *jobj_digests;
|
||||
int r = -ENOENT;
|
||||
int keyslot_digest, segment_digest;
|
||||
|
||||
/* no need to check anything */
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
return 0;
|
||||
|
||||
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1 ||
|
||||
snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
|
||||
keyslot_digest = LUKS2_digest_by_keyslot(NULL, hdr, keyslot);
|
||||
if (keyslot_digest < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* empty set is subset of any set and it'd be wrong */
|
||||
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
|
||||
r = LUKS2_digests_by_keyslot(NULL, hdr, keyslot, keyslot_digests);
|
||||
if (r)
|
||||
return r;
|
||||
segment_digest = LUKS2_digest_by_segment(NULL, hdr, segment);
|
||||
if (segment_digest < 0)
|
||||
return segment_digest;
|
||||
|
||||
/* empty set can't be superset of non-empty one */
|
||||
if (digests_by_segment(jobj_digests, segment_name, segment_digests))
|
||||
return r;
|
||||
|
||||
/*
|
||||
* keyslot may activate segment if set of digests for keyslot
|
||||
* is actually subset of set of digests for segment
|
||||
*/
|
||||
return is_subset(segment_digests, keyslot_digests, LUKS2_DIGEST_MAX) ? 0 : -ENOENT;
|
||||
return segment_digest == keyslot_digest ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
/* Number of keyslots assigned to a segment or all keyslots for CRYPT_ANY_SEGMENT */
|
||||
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
|
||||
{
|
||||
int num = 0;
|
||||
@@ -160,7 +102,6 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
|
||||
|
||||
/* keyslot digests must be subset of segment digests */
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
UNUSED(val);
|
||||
if (!LUKS2_keyslot_for_segment(hdr, atoi(slot), segment))
|
||||
@@ -170,18 +111,97 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
|
||||
return num;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd)
|
||||
{
|
||||
const char *cipher = crypt_get_cipher(cd);
|
||||
|
||||
/* Keyslot is already authenticated; we cannot use integrity tags here */
|
||||
if (crypt_get_integrity_tag_size(cd) || !cipher)
|
||||
return 1;
|
||||
|
||||
/* Wrapped key schemes cannot be used for keyslot encryption */
|
||||
if (crypt_cipher_wrapped_key(cipher))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
size_t key_size, struct luks2_keyslot_params *params)
|
||||
{
|
||||
int r, integrity_key_size = crypt_get_integrity_key_size(cd);
|
||||
const struct crypt_pbkdf_type *pbkdf = crypt_get_pbkdf_type(cd);
|
||||
|
||||
if (!hdr || !pbkdf || !params)
|
||||
return -EINVAL;
|
||||
|
||||
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
|
||||
params->area_type = LUKS2_KEYSLOT_AREA_RAW;
|
||||
|
||||
/* set keyslot AF parameters */
|
||||
/* currently we use hash for AF from pbkdf settings */
|
||||
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash),
|
||||
"%s", pbkdf->hash);
|
||||
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
|
||||
return -EINVAL;
|
||||
|
||||
params->af.luks1.stripes = 4000;
|
||||
|
||||
/* set keyslot area encryption parameters */
|
||||
/* short circuit authenticated encryption hardcoded defaults */
|
||||
if (LUKS2_keyslot_cipher_incompatible(cd) || key_size == 0) {
|
||||
// FIXME: fixed cipher and key size can be wrong
|
||||
snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption),
|
||||
"aes-xts-plain64");
|
||||
params->area.raw.key_size = 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption),
|
||||
"%s", LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT));
|
||||
if (r < 0 || (size_t)r >= sizeof(params->area.raw.encryption))
|
||||
return -EINVAL;
|
||||
|
||||
/* Slot encryption tries to use the same key size as for the main algorithm */
|
||||
if ((size_t)integrity_key_size > key_size)
|
||||
return -EINVAL;
|
||||
params->area.raw.key_size = key_size - integrity_key_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_unbound(struct luks2_hdr *hdr, int keyslot)
|
||||
{
|
||||
json_object *jobj_digest, *jobj_segments;
|
||||
int digest = LUKS2_digest_by_keyslot(NULL, hdr, keyslot);
|
||||
|
||||
if (digest < 0)
|
||||
return 0;
|
||||
|
||||
if (!(jobj_digest = LUKS2_get_digest_jobj(hdr, digest)))
|
||||
return 0;
|
||||
|
||||
json_object_object_get_ex(jobj_digest, "segments", &jobj_segments);
|
||||
if (!jobj_segments || !json_object_is_type(jobj_segments, json_type_array) ||
|
||||
json_object_array_length(jobj_segments) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
|
||||
{
|
||||
crypt_keyslot_info ki;
|
||||
|
||||
if(keyslot >= LUKS2_KEYSLOTS_MAX || keyslot < 0)
|
||||
return CRYPT_SLOT_INVALID;
|
||||
|
||||
ki = LUKS2_keyslot_active(hdr, keyslot);
|
||||
if (ki != CRYPT_SLOT_ACTIVE)
|
||||
return ki;
|
||||
if (!LUKS2_get_keyslot_jobj(hdr, keyslot))
|
||||
return CRYPT_SLOT_INACTIVE;
|
||||
|
||||
if (LUKS2_keyslot_active_count(hdr, CRYPT_DEFAULT_SEGMENT) == 1 && !LUKS2_keyslot_for_segment(hdr, keyslot, CRYPT_DEFAULT_SEGMENT))
|
||||
if (LUKS2_keyslot_unbound(hdr, keyslot))
|
||||
return CRYPT_SLOT_UNBOUND;
|
||||
|
||||
if (LUKS2_keyslot_active_count(hdr, CRYPT_DEFAULT_SEGMENT) == 1 &&
|
||||
!LUKS2_keyslot_for_segment(hdr, keyslot, CRYPT_DEFAULT_SEGMENT))
|
||||
return CRYPT_SLOT_ACTIVE_LAST;
|
||||
|
||||
return CRYPT_SLOT_ACTIVE;
|
||||
@@ -229,6 +249,12 @@ static int LUKS2_open_and_verify(struct crypt_device *cd,
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -ENOENT;
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg("Keyslot %d validation failed.", keyslot);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = LUKS2_keyslot_for_segment(hdr, keyslot, segment);
|
||||
if (r) {
|
||||
if (r == -ENOENT)
|
||||
@@ -315,7 +341,7 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
password, password_len, segment, vk);
|
||||
if (r_prio >= 0)
|
||||
r = r_prio;
|
||||
else if (r_prio < 0 && (r_prio != -EPERM) && (r_prio != -ENOENT))
|
||||
else if (r_prio != -EPERM && r_prio != -ENOENT)
|
||||
r = r_prio;
|
||||
else
|
||||
r = LUKS2_keyslot_open_priority(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
|
||||
@@ -334,7 +360,8 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
const struct volume_key *vk)
|
||||
const struct volume_key *vk,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int r;
|
||||
@@ -348,13 +375,21 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = h->alloc(cd, keyslot, vk->keylength);
|
||||
r = h->alloc(cd, keyslot, vk->keylength, params);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -EINVAL;
|
||||
|
||||
r = h->validate(cd, keyslot);
|
||||
r = h->update(cd, keyslot, params);
|
||||
if (r) {
|
||||
log_dbg("Failed to update keyslot %d json.", keyslot);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg("Keyslot validation failed.");
|
||||
return r;
|
||||
@@ -391,7 +426,7 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
/* Just check that nobody uses the metadata now */
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."),
|
||||
device_path(device));
|
||||
return r;
|
||||
}
|
||||
@@ -408,11 +443,11 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
area_length, area_length, NULL, NULL);
|
||||
if (r) {
|
||||
if (r == -EACCES) {
|
||||
log_err(cd, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(cd, _("Cannot write to device %s, permission denied."),
|
||||
device_path(device));
|
||||
r = -EINVAL;
|
||||
} else
|
||||
log_err(cd, _("Cannot wipe device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Cannot wipe device %s."), device_path(device));
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -475,3 +510,119 @@ int LUKS2_keyslot_priority_set(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
|
||||
}
|
||||
|
||||
int placeholder_keyslot_alloc(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
uint64_t area_offset,
|
||||
uint64_t area_length,
|
||||
size_t volume_key_len)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
char num[16];
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
|
||||
|
||||
log_dbg("Allocating placeholder keyslot %d for LUKS1 down conversion.", keyslot);
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (LUKS2_get_keyslot_jobj(hdr, keyslot))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = json_object_new_object();
|
||||
json_object_object_add(jobj_keyslot, "type", json_object_new_string("placeholder"));
|
||||
/*
|
||||
* key_size = -1 makes placeholder keyslot impossible to pass validation.
|
||||
* It's a safeguard against accidentally storing temporary conversion
|
||||
* LUKS2 header.
|
||||
*/
|
||||
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(-1));
|
||||
|
||||
/* Area object */
|
||||
jobj_area = json_object_new_object();
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_length));
|
||||
json_object_object_add(jobj_keyslot, "area", jobj_area);
|
||||
|
||||
snprintf(num, sizeof(num), "%d", keyslot);
|
||||
|
||||
json_object_object_add(jobj_keyslots, num, jobj_keyslot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned LUKS2_get_keyslot_digests_count(json_object *hdr_jobj, int keyslot)
|
||||
{
|
||||
char num[16];
|
||||
json_object *jobj_digests, *jobj_keyslots;
|
||||
unsigned count = 0;
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "digests", &jobj_digests))
|
||||
return 0;
|
||||
|
||||
if (snprintf(num, sizeof(num), "%u", keyslot) < 0)
|
||||
return 0;
|
||||
|
||||
json_object_object_foreach(jobj_digests, key, val) {
|
||||
UNUSED(key);
|
||||
json_object_object_get_ex(val, "keyslots", &jobj_keyslots);
|
||||
if (LUKS2_array_jobj(jobj_keyslots, num))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* run only on header that passed basic format validation */
|
||||
int LUKS2_keyslots_validate(json_object *hdr_jobj)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int keyslot;
|
||||
json_object *jobj_keyslots, *jobj_type;
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
keyslot = atoi(slot);
|
||||
json_object_object_get_ex(val, "type", &jobj_type);
|
||||
h = LUKS2_keyslot_handler_type(NULL, json_object_get_string(jobj_type));
|
||||
if (!h)
|
||||
continue;
|
||||
if (h->validate && h->validate(NULL, val)) {
|
||||
log_dbg("Keyslot type %s validation failed on keyslot %d.", h->name, keyslot);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(h->name, "luks2") && LUKS2_get_keyslot_digests_count(hdr_jobj, keyslot) != 1) {
|
||||
log_dbg("Keyslot %d is not assigned to exactly 1 digest.", keyslot);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LUKS2_keyslots_repair(json_object *jobj_keyslots)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
json_object *jobj_type;
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
UNUSED(slot);
|
||||
if (!json_object_is_type(val, json_type_object) ||
|
||||
!json_object_object_get_ex(val, "type", &jobj_type) ||
|
||||
!json_object_is_type(jobj_type, json_type_string))
|
||||
continue;
|
||||
|
||||
h = LUKS2_keyslot_handler_type(NULL, json_object_get_string(jobj_type));
|
||||
if (h && h->repair)
|
||||
h->repair(NULL, val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, LUKS2 type keyslot handler
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -37,7 +37,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
|
||||
int r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device));
|
||||
return r;
|
||||
}
|
||||
r = LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
|
||||
@@ -66,17 +66,16 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."),
|
||||
device_path(device));
|
||||
return r;
|
||||
}
|
||||
|
||||
devfd = device_open_locked(device, O_RDWR);
|
||||
if (devfd >= 0) {
|
||||
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
|
||||
write_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), src,
|
||||
srcLength) == -1)
|
||||
if (write_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), src,
|
||||
srcLength, sector * SECTOR_SIZE) < 0)
|
||||
r = -EIO;
|
||||
else
|
||||
r = 0;
|
||||
@@ -87,7 +86,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
device_write_unlock(device);
|
||||
|
||||
if (r)
|
||||
log_err(cd, _("IO error while encrypting keyslot.\n"));
|
||||
log_err(cd, _("IO error while encrypting keyslot."));
|
||||
|
||||
return r;
|
||||
#endif
|
||||
@@ -101,7 +100,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
|
||||
int r = device_read_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire read lock on device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Failed to acquire read lock on device %s."), device_path(device));
|
||||
return r;
|
||||
}
|
||||
r = LUKS_decrypt_from_storage(dst, dstLength, cipher, cipher_mode, vk, sector, cd);
|
||||
@@ -124,7 +123,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
|
||||
r = device_read_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire read lock on device %s."),
|
||||
device_path(device));
|
||||
crypt_storage_destroy(s);
|
||||
return r;
|
||||
@@ -132,9 +131,9 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
|
||||
devfd = device_open_locked(device, O_RDONLY);
|
||||
if (devfd >= 0) {
|
||||
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
|
||||
read_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), dst, dstLength) == -1)
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), dst,
|
||||
dstLength, sector * SECTOR_SIZE) < 0)
|
||||
r = -EIO;
|
||||
else
|
||||
r = 0;
|
||||
@@ -148,13 +147,64 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
if (!r)
|
||||
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
|
||||
else
|
||||
log_err(cd, _("IO error while decrypting keyslot.\n"));
|
||||
log_err(cd, _("IO error while decrypting keyslot."));
|
||||
|
||||
crypt_storage_destroy(s);
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int luks2_keyslot_get_pbkdf_params(json_object *jobj_keyslot,
|
||||
struct crypt_pbkdf_type *pbkdf, char *salt)
|
||||
{
|
||||
json_object *jobj_kdf, *jobj1, *jobj2;
|
||||
size_t salt_len;
|
||||
|
||||
if (!jobj_keyslot || !pbkdf)
|
||||
return -EINVAL;
|
||||
|
||||
memset(pbkdf, 0, sizeof(*pbkdf));
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
pbkdf->type = json_object_get_string(jobj1);
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "hash", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->hash = json_object_get_string(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "iterations", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->iterations = json_object_get_int(jobj2);
|
||||
pbkdf->max_memory_kb = 0;
|
||||
pbkdf->parallel_threads = 0;
|
||||
} else {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "time", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->iterations = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "memory", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->max_memory_kb = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "cpus", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->parallel_threads = json_object_get_int(jobj2);
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj2))
|
||||
return -EINVAL;
|
||||
salt_len = LUKS_SALTSIZE;
|
||||
if (!base64_decode(json_object_get_string(jobj2),
|
||||
json_object_get_string_len(jobj2),
|
||||
salt, &salt_len))
|
||||
return -EINVAL;
|
||||
if (salt_len != LUKS_SALTSIZE)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
json_object *jobj_keyslot,
|
||||
const char *password, size_t passwordLen,
|
||||
@@ -162,11 +212,12 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
{
|
||||
struct volume_key *derived_key;
|
||||
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
char *AfKey = NULL, *salt_base64 = NULL;
|
||||
char *AfKey = NULL;
|
||||
const char *af_hash = NULL;
|
||||
size_t AFEKSize, keyslot_key_len;
|
||||
json_object *jobj2, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
uint64_t area_offset;
|
||||
const struct crypt_pbkdf_type *pbkdf;
|
||||
struct crypt_pbkdf_type pbkdf;
|
||||
int r;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
@@ -174,6 +225,12 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
|
||||
/* prevent accidental volume key size change after allocation */
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "key_size", &jobj2))
|
||||
return -EINVAL;
|
||||
if (json_object_get_int(jobj2) != (int)volume_key_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "offset", &jobj2))
|
||||
return -EINVAL;
|
||||
area_offset = json_object_get_uint64(jobj2);
|
||||
@@ -188,52 +245,27 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
keyslot_key_len = json_object_get_int(jobj2);
|
||||
|
||||
pbkdf = crypt_get_pbkdf_type(cd);
|
||||
if (!pbkdf)
|
||||
if (!json_object_object_get_ex(jobj_af, "hash", &jobj2))
|
||||
return -EINVAL;
|
||||
af_hash = json_object_get_string(jobj2);
|
||||
|
||||
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, volume_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
|
||||
} else {
|
||||
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
|
||||
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
|
||||
}
|
||||
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
|
||||
/*
|
||||
* Get salt and allocate derived key storage.
|
||||
* Allocate derived key storage.
|
||||
*/
|
||||
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
base64_encode_alloc(salt, LUKS_SALTSIZE, &salt_base64);
|
||||
if (!salt_base64)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(salt_base64));
|
||||
free(salt_base64);
|
||||
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
|
||||
json_object_object_add(jobj_af, "hash", json_object_new_string(pbkdf->hash));
|
||||
|
||||
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
|
||||
if (!derived_key)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* Calculate keyslot content, split and store it to keyslot area.
|
||||
*/
|
||||
r = crypt_pbkdf(pbkdf->type, pbkdf->hash, password, passwordLen,
|
||||
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
|
||||
salt, LUKS_SALTSIZE,
|
||||
derived_key->key, derived_key->keylength,
|
||||
pbkdf->iterations, pbkdf->max_memory_kb,
|
||||
pbkdf->parallel_threads);
|
||||
pbkdf.iterations, pbkdf.max_memory_kb,
|
||||
pbkdf.parallel_threads);
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(derived_key);
|
||||
return r;
|
||||
@@ -247,7 +279,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = AF_split(volume_key, AfKey, volume_key_len, LUKS_STRIPES, pbkdf->hash);
|
||||
r = AF_split(volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
|
||||
|
||||
if (r == 0) {
|
||||
log_dbg("Updating keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
@@ -261,7 +293,6 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
JSON_DBG(jobj_keyslot, "Keyslot JSON");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -271,53 +302,21 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
char *volume_key, size_t volume_key_len)
|
||||
{
|
||||
struct volume_key *derived_key;
|
||||
struct crypt_pbkdf_type pbkdf;
|
||||
char *AfKey;
|
||||
size_t AFEKSize;
|
||||
const char *hash = NULL, *af_hash = NULL, *kdf;
|
||||
const char *af_hash = NULL;
|
||||
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
json_object *jobj1, *jobj2, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
uint32_t iterations, memory, parallel;
|
||||
json_object *jobj2, *jobj_af, *jobj_area;
|
||||
uint64_t area_offset;
|
||||
size_t salt_len, keyslot_key_len;
|
||||
size_t keyslot_key_len;
|
||||
int r;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
kdf = json_object_get_string(jobj1);
|
||||
if (!strcmp(kdf, CRYPT_KDF_PBKDF2)) {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "hash", &jobj2))
|
||||
return -EINVAL;
|
||||
hash = json_object_get_string(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "iterations", &jobj2))
|
||||
return -EINVAL;
|
||||
iterations = json_object_get_int(jobj2);
|
||||
memory = 0;
|
||||
parallel = 0;
|
||||
} else {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "time", &jobj2))
|
||||
return -EINVAL;
|
||||
iterations = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "memory", &jobj2))
|
||||
return -EINVAL;
|
||||
memory = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "cpus", &jobj2))
|
||||
return -EINVAL;
|
||||
parallel = json_object_get_int(jobj2);
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj2))
|
||||
return -EINVAL;
|
||||
salt_len = LUKS_SALTSIZE;
|
||||
if (!base64_decode(json_object_get_string(jobj2),
|
||||
json_object_get_string_len(jobj2),
|
||||
salt, &salt_len))
|
||||
return -EINVAL;
|
||||
if (salt_len != LUKS_SALTSIZE)
|
||||
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_af, "hash", &jobj2))
|
||||
@@ -354,10 +353,11 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
/*
|
||||
* Calculate derived key, decrypt keyslot content and merge it.
|
||||
*/
|
||||
r = crypt_pbkdf(kdf, hash, password, passwordLen,
|
||||
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
|
||||
salt, LUKS_SALTSIZE,
|
||||
derived_key->key, derived_key->keylength,
|
||||
iterations, memory, parallel);
|
||||
pbkdf.iterations, pbkdf.max_memory_kb,
|
||||
pbkdf.parallel_threads);
|
||||
|
||||
if (r == 0) {
|
||||
log_dbg("Reading keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
@@ -375,28 +375,101 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
/*
|
||||
* currently we support update of only:
|
||||
*
|
||||
* - af hash function
|
||||
* - kdf params
|
||||
*/
|
||||
static int luks2_keyslot_update_json(struct crypt_device *cd,
|
||||
json_object *jobj_keyslot,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
const struct crypt_pbkdf_type *pbkdf;
|
||||
json_object *jobj_af, *jobj_area, *jobj_kdf, *jobj1;
|
||||
char salt[LUKS_SALTSIZE], *salt_base64 = NULL;
|
||||
int r, keyslot_key_len;
|
||||
|
||||
/* jobj_keyslot is not yet validated */
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
|
||||
!json_object_object_get_ex(jobj_area, "key_size", &jobj1))
|
||||
return -EINVAL;
|
||||
|
||||
/* we do not allow any 'area' object modifications yet */
|
||||
keyslot_key_len = json_object_get_int(jobj1);
|
||||
if (keyslot_key_len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
pbkdf = crypt_get_pbkdf_type(cd);
|
||||
if (!pbkdf)
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, keyslot_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* refresh whole 'kdf' object */
|
||||
jobj_kdf = json_object_new_object();
|
||||
if (!jobj_kdf)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
|
||||
} else {
|
||||
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
|
||||
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
|
||||
}
|
||||
json_object_object_add(jobj_keyslot, "kdf", jobj_kdf);
|
||||
|
||||
/*
|
||||
* Regenerate salt and add it in 'kdf' object
|
||||
*/
|
||||
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
base64_encode_alloc(salt, LUKS_SALTSIZE, &salt_base64);
|
||||
if (!salt_base64)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(salt_base64));
|
||||
free(salt_base64);
|
||||
|
||||
/* update 'af' hash */
|
||||
json_object_object_add(jobj_af, "hash", json_object_new_string(params->af.luks1.hash));
|
||||
|
||||
JSON_DBG(jobj_keyslot, "Keyslot JSON");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
size_t volume_key_len)
|
||||
size_t volume_key_len,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
const struct crypt_pbkdf_type *pbkdf;
|
||||
char area_offset_string[24], area_length_string[24];
|
||||
char cipher[2 * MAX_CIPHER_LEN + 1], num[16];
|
||||
char num[16];
|
||||
uint64_t area_offset, area_length;
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
size_t keyslot_key_len;
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_af, *jobj_area;
|
||||
int r;
|
||||
|
||||
log_dbg("Trying to allocate LUKS2 keyslot %d.", keyslot);
|
||||
|
||||
if (!params || params->area_type != LUKS2_KEYSLOT_AREA_RAW ||
|
||||
params->af_type != LUKS2_KEYSLOT_AF_LUKS1) {
|
||||
log_dbg("Invalid LUKS2 keyslot parameters.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT)
|
||||
keyslot = LUKS2_keyslot_find_empty(hdr, "luks2");
|
||||
|
||||
if (keyslot < 0 || keyslot > LUKS2_KEYSLOTS_MAX)
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return -ENOMEM;
|
||||
|
||||
if (LUKS2_get_keyslot_jobj(hdr, keyslot)) {
|
||||
@@ -411,74 +484,40 @@ int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
pbkdf = crypt_get_pbkdf_type(cd);
|
||||
if (!pbkdf)
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, volume_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
jobj_keyslot = json_object_new_object();
|
||||
json_object_object_add(jobj_keyslot, "type", json_object_new_string("luks2"));
|
||||
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(volume_key_len));
|
||||
|
||||
/* PBKDF object */
|
||||
jobj_kdf = json_object_new_object();
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(""));
|
||||
} else {
|
||||
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
|
||||
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(""));
|
||||
}
|
||||
json_object_object_add(jobj_keyslot, "kdf", jobj_kdf);
|
||||
|
||||
/* AF object */
|
||||
jobj_af = json_object_new_object();
|
||||
json_object_object_add(jobj_af, "type", json_object_new_string("luks1"));
|
||||
json_object_object_add(jobj_af, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_af, "stripes", json_object_new_int(4000));
|
||||
json_object_object_add(jobj_af, "stripes", json_object_new_int(params->af.luks1.stripes));
|
||||
json_object_object_add(jobj_keyslot, "af", jobj_af);
|
||||
|
||||
/* Area object */
|
||||
jobj_area = json_object_new_object();
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("raw"));
|
||||
|
||||
/* Slot encryption tries to use the same key size as fot the main algorithm */
|
||||
keyslot_key_len = volume_key_len - crypt_get_integrity_key_size(cd);
|
||||
|
||||
/* Cannot use metadata tags in keyslot */
|
||||
if (crypt_get_integrity_tag_size(cd)) {
|
||||
snprintf(cipher, sizeof(cipher), "aes-xts-plain64"); // FIXME: fixed cipher and key size can be wrong
|
||||
keyslot_key_len = 32;
|
||||
} else if (crypt_get_cipher_mode(cd))
|
||||
snprintf(cipher, sizeof(cipher), "%s-%s", crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
|
||||
else
|
||||
snprintf(cipher, sizeof(cipher), "%s", crypt_get_cipher(cd));
|
||||
|
||||
json_object_object_add(jobj_area, "encryption", json_object_new_string(cipher));
|
||||
json_object_object_add(jobj_area, "key_size", json_object_new_int(keyslot_key_len));
|
||||
uint64_to_str(area_offset_string, sizeof(area_offset_string), &area_offset);
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_string(area_offset_string));
|
||||
uint64_to_str(area_length_string, sizeof(area_length_string), &area_length);
|
||||
json_object_object_add(jobj_area, "size", json_object_new_string(area_length_string));
|
||||
json_object_object_add(jobj_area, "encryption", json_object_new_string(params->area.raw.encryption));
|
||||
json_object_object_add(jobj_area, "key_size", json_object_new_int(params->area.raw.key_size));
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_length));
|
||||
json_object_object_add(jobj_keyslot, "area", jobj_area);
|
||||
|
||||
snprintf(num, sizeof(num), "%d", keyslot);
|
||||
|
||||
json_object_object_add(jobj_keyslots, num, jobj_keyslot);
|
||||
if (LUKS2_check_json_size(hdr)) {
|
||||
|
||||
r = luks2_keyslot_update_json(cd, jobj_keyslot, params);
|
||||
|
||||
if (!r && LUKS2_check_json_size(hdr)) {
|
||||
log_dbg("Not enough space in header json area for new keyslot.");
|
||||
json_object_object_del(jobj_keyslots, num);
|
||||
return -ENOSPC;
|
||||
r = -ENOSPC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (r)
|
||||
json_object_object_del(jobj_keyslots, num);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_open(struct crypt_device *cd,
|
||||
@@ -505,6 +544,10 @@ static int luks2_keyslot_open(struct crypt_device *cd,
|
||||
volume_key, volume_key_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function must not modify json.
|
||||
* It's called after luks2 keyslot validation.
|
||||
*/
|
||||
static int luks2_keyslot_store(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
@@ -579,7 +622,7 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
log_std(cd, "\tIterations: %" PRIu64 "\n", json_object_get_uint64(jobj1));
|
||||
} else {
|
||||
json_object_object_get_ex(jobj_kdf, "time", &jobj1);
|
||||
log_std(cd, "\tTime: %" PRIu64 "\n", json_object_get_int64(jobj1));
|
||||
log_std(cd, "\tTime cost: %" PRIu64 "\n", json_object_get_int64(jobj1));
|
||||
|
||||
json_object_object_get_ex(jobj_kdf, "memory", &jobj1);
|
||||
log_std(cd, "\tMemory: %" PRIu64 "\n", json_object_get_int64(jobj1));
|
||||
@@ -604,59 +647,47 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int contains(json_object *jobj, const char *key, json_type type)
|
||||
static int luks2_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
|
||||
{
|
||||
json_object *sobj;
|
||||
json_object *jobj_kdf, *jobj_af, *jobj_area, *jobj1;
|
||||
const char *type;
|
||||
int count;
|
||||
|
||||
if (!json_object_object_get_ex(jobj, key, &sobj) ||
|
||||
!json_object_is_type(sobj, type))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslot, *jobj_kdf, *jobj_af, *jobj_area, *jobj1;
|
||||
char num[16];
|
||||
|
||||
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
snprintf(num, sizeof(num), "%d", keyslot);
|
||||
if (LUKS2_keyslot_validate(hdr->jobj, jobj_keyslot, num))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
count = json_object_object_length(jobj_kdf);
|
||||
|
||||
if (!strcmp(json_object_get_string(jobj1), CRYPT_KDF_PBKDF2)) {
|
||||
if (!contains(jobj_kdf, "hash", json_type_string) ||
|
||||
!contains(jobj_kdf, "iterations", json_type_int) ||
|
||||
!contains(jobj_kdf, "salt", json_type_string))
|
||||
jobj1 = json_contains(jobj_kdf, "", "kdf section", "type", json_type_string);
|
||||
if (!jobj1)
|
||||
return -EINVAL;
|
||||
type = json_object_get_string(jobj1);
|
||||
|
||||
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
|
||||
if (count != 4 || /* type, salt, hash, iterations only */
|
||||
!json_contains(jobj_kdf, "kdf type", type, "hash", json_type_string) ||
|
||||
!json_contains(jobj_kdf, "kdf type", type, "iterations", json_type_int) ||
|
||||
!json_contains(jobj_kdf, "kdf type", type, "salt", json_type_string))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!contains(jobj_kdf, "time", json_type_int) ||
|
||||
!contains(jobj_kdf, "memory", json_type_int) ||
|
||||
!contains(jobj_kdf, "cpus", json_type_int) ||
|
||||
!contains(jobj_kdf, "salt", json_type_string))
|
||||
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
|
||||
if (count != 5 || /* type, salt, time, memory, cpus only */
|
||||
!json_contains(jobj_kdf, "kdf type", type, "time", json_type_int) ||
|
||||
!json_contains(jobj_kdf, "kdf type", type, "memory", json_type_int) ||
|
||||
!json_contains(jobj_kdf, "kdf type", type, "cpus", json_type_int) ||
|
||||
!json_contains(jobj_kdf, "kdf type", type, "salt", json_type_string))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_af, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
if (!strcmp(json_object_get_string(jobj1), "luks1")) {
|
||||
if (!contains(jobj_af, "hash", json_type_string) ||
|
||||
!contains(jobj_af, "stripes", json_type_int))
|
||||
if (!json_contains(jobj_af, "", "luks1 af", "hash", json_type_string) ||
|
||||
!json_contains(jobj_af, "", "luks1 af", "stripes", json_type_int))
|
||||
return -EINVAL;
|
||||
} else
|
||||
return -EINVAL;
|
||||
@@ -665,10 +696,10 @@ static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
|
||||
if (!json_object_object_get_ex(jobj_area, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
if (!strcmp(json_object_get_string(jobj1), "raw")) {
|
||||
if (!contains(jobj_area, "encryption", json_type_string) ||
|
||||
!contains(jobj_area, "key_size", json_type_int) ||
|
||||
!contains(jobj_area, "offset", json_type_string) ||
|
||||
!contains(jobj_area, "size", json_type_string))
|
||||
if (!json_contains(jobj_area, "area", "raw type", "encryption", json_type_string) ||
|
||||
!json_contains(jobj_area, "area", "raw type", "key_size", json_type_int) ||
|
||||
!json_contains(jobj_area, "area", "raw type", "offset", json_type_string) ||
|
||||
!json_contains(jobj_area, "area", "raw type", "size", json_type_string))
|
||||
return -EINVAL;
|
||||
} else
|
||||
return -EINVAL;
|
||||
@@ -676,12 +707,78 @@ static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_update(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslot;
|
||||
int r;
|
||||
|
||||
log_dbg("Updating LUKS2 keyslot %d.", keyslot);
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
r = luks2_keyslot_update_json(cd, jobj_keyslot, params);
|
||||
|
||||
if (!r && LUKS2_check_json_size(hdr)) {
|
||||
log_dbg("Not enough space in header json area for updated keyslot %d.", keyslot);
|
||||
r = -ENOSPC;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void luks2_keyslot_repair(struct crypt_device *cd, json_object *jobj_keyslot)
|
||||
{
|
||||
const char *type;
|
||||
json_object *jobj_kdf, *jobj_type;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
!json_object_is_type(jobj_kdf, json_type_object))
|
||||
return;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj_type) ||
|
||||
!json_object_is_type(jobj_type, json_type_string))
|
||||
return;
|
||||
|
||||
type = json_object_get_string(jobj_type);
|
||||
|
||||
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
|
||||
/* type, salt, hash, iterations only */
|
||||
json_object_object_foreach(jobj_kdf, key, val) {
|
||||
UNUSED(val);
|
||||
if (!strcmp(key, "type") || !strcmp(key, "salt") ||
|
||||
!strcmp(key, "hash") || !strcmp(key, "iterations"))
|
||||
continue;
|
||||
json_object_object_del(jobj_kdf, key);
|
||||
}
|
||||
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
|
||||
/* type, salt, time, memory, cpus only */
|
||||
json_object_object_foreach(jobj_kdf, key, val) {
|
||||
UNUSED(val);
|
||||
if (!strcmp(key, "type") || !strcmp(key, "salt") ||
|
||||
!strcmp(key, "time") || !strcmp(key, "memory") ||
|
||||
!strcmp(key, "cpus"))
|
||||
continue;
|
||||
json_object_object_del(jobj_kdf, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const keyslot_handler luks2_keyslot = {
|
||||
.name = "luks2",
|
||||
.alloc = luks2_keyslot_alloc,
|
||||
.update = luks2_keyslot_update,
|
||||
.open = luks2_keyslot_open,
|
||||
.store = luks2_keyslot_store,
|
||||
.wipe = luks2_keyslot_wipe,
|
||||
.dump = luks2_keyslot_dump,
|
||||
.validate = luks2_keyslot_validate,
|
||||
.repair = luks2_keyslot_repair
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, LUKS1 conversion code
|
||||
*
|
||||
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Ondrej Kozina. All rights reserved.
|
||||
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Ondrej Kozina. All rights reserved.
|
||||
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
|
||||
{
|
||||
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L], num[24];
|
||||
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
|
||||
size_t base64_len;
|
||||
struct json_object *keyslot_obj, *field, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
uint64_t offset, area_size, offs_a, offs_b, length;
|
||||
@@ -83,8 +83,8 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
|
||||
}
|
||||
area_size = offs_b - offs_a;
|
||||
json_object_object_add(jobj_area, "key_size", json_object_new_int(hdr_v1->keyBytes));
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_string(uint64_to_str(num, sizeof(num), &offset)));
|
||||
json_object_object_add(jobj_area, "size", json_object_new_string(uint64_to_str(num, sizeof(num), &area_size)));
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_uint64(offset));
|
||||
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_size));
|
||||
json_object_object_add(keyslot_obj, "area", jobj_area);
|
||||
|
||||
*keyslot_object = keyslot_obj;
|
||||
@@ -121,7 +121,6 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
|
||||
{
|
||||
const char *c;
|
||||
char cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
|
||||
char num[24]; /* uint64_t in string */
|
||||
struct json_object *segment_obj, *field;
|
||||
uint64_t number;
|
||||
|
||||
@@ -140,7 +139,7 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
|
||||
/* offset field */
|
||||
number = (uint64_t)hdr_v1->payloadOffset * SECTOR_SIZE;
|
||||
|
||||
field = json_object_new_string(uint64_to_str(num, sizeof(num), &number));
|
||||
field = json_object_new_uint64(number);
|
||||
if (!field) {
|
||||
json_object_put(segment_obj);
|
||||
return -ENOMEM;
|
||||
@@ -348,7 +347,6 @@ static int json_luks1_digests(const struct luks_phdr *hdr_v1, struct json_object
|
||||
|
||||
static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks1_object, uint64_t keyslots_size)
|
||||
{
|
||||
char num[24];
|
||||
int r;
|
||||
struct json_object *luks1_obj, *field;
|
||||
uint64_t json_size;
|
||||
@@ -399,10 +397,8 @@ static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks
|
||||
json_object_object_add(luks1_obj, "config", field);
|
||||
|
||||
json_size = LUKS2_HDR_16K_LEN - LUKS2_HDR_BIN_LEN;
|
||||
json_object_object_add(field, "json_size",
|
||||
json_object_new_string(uint64_to_str(num, sizeof(num), &json_size)));
|
||||
json_object_object_add(field, "keyslots_size",
|
||||
json_object_new_string(uint64_to_str(num, sizeof(num), &keyslots_size)));
|
||||
json_object_object_add(field, "json_size", json_object_new_uint64(json_size));
|
||||
json_object_object_add(field, "keyslots_size", json_object_new_uint64(keyslots_size));
|
||||
|
||||
*luks1_object = luks1_obj;
|
||||
return 0;
|
||||
@@ -410,7 +406,6 @@ static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks
|
||||
|
||||
static void move_keyslot_offset(json_object *jobj, int offset_add)
|
||||
{
|
||||
char num[24];
|
||||
json_object *jobj1, *jobj2, *jobj_area;
|
||||
uint64_t offset = 0;
|
||||
|
||||
@@ -420,7 +415,7 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
|
||||
json_object_object_get_ex(val, "area", &jobj_area);
|
||||
json_object_object_get_ex(jobj_area, "offset", &jobj2);
|
||||
offset = json_object_get_uint64(jobj2) + offset_add;
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_string(uint64_to_str(num, sizeof(num), &offset)));
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_uint64(offset));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,43 +425,47 @@ static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
|
||||
{
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
void *buf = NULL;
|
||||
int devfd = -1;
|
||||
int r = -EIO, devfd = -1;
|
||||
|
||||
log_dbg("Moving keyslot areas of size %zu from %jd to %jd.",
|
||||
buf_size, (intmax_t)offset_from, (intmax_t)offset_to);
|
||||
|
||||
// FIXME: export aligned_malloc from utils
|
||||
if (posix_memalign(&buf, crypt_getpagesize(), buf_size))
|
||||
return -ENOMEM;
|
||||
|
||||
devfd = device_open(device, O_RDWR);
|
||||
if (devfd == -1) {
|
||||
log_dbg("Cannot open device %s.", device_path(device));
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* This can safely fail (for block devices). It only allocates space if it is possible. */
|
||||
if (posix_fallocate(devfd, offset_to, buf_size))
|
||||
log_dbg("Preallocation (fallocate) of new keyslot area not available.");
|
||||
|
||||
/* Try to read *new* area to check that area is there (trimmed backup). */
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), buf, buf_size,
|
||||
offset_to)!= (ssize_t)buf_size)
|
||||
goto out;
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), buf, buf_size,
|
||||
offset_from)!= (ssize_t)buf_size) {
|
||||
close(devfd);
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
offset_from)!= (ssize_t)buf_size)
|
||||
goto out;
|
||||
|
||||
if (write_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), buf, buf_size,
|
||||
offset_to) != (ssize_t)buf_size) {
|
||||
close(devfd);
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
offset_to) != (ssize_t)buf_size)
|
||||
goto out;
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
close(devfd);
|
||||
crypt_memzero(buf, buf_size);
|
||||
free(buf);
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int luks_header_in_use(struct crypt_device *cd)
|
||||
@@ -475,11 +474,41 @@ static int luks_header_in_use(struct crypt_device *cd)
|
||||
|
||||
r = lookup_dm_dev_by_uuid(crypt_get_uuid(cd), crypt_get_type(cd));
|
||||
if (r < 0)
|
||||
log_err(cd, _("Can not check status of device with uuid: %s.\n"), crypt_get_uuid(cd));
|
||||
log_err(cd, _("Can not check status of device with uuid: %s."), crypt_get_uuid(cd));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Check if there is a luksmeta area (foreign metadata created by the luksmeta package) */
|
||||
static int luksmeta_header_present(struct crypt_device *cd, off_t luks1_size)
|
||||
{
|
||||
static const uint8_t LM_MAGIC[] = { 'L', 'U', 'K', 'S', 'M', 'E', 'T', 'A' };
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
void *buf = NULL;
|
||||
int devfd, r = 0;
|
||||
|
||||
if (posix_memalign(&buf, crypt_getpagesize(), sizeof(LM_MAGIC)))
|
||||
return -ENOMEM;
|
||||
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
if (devfd == -1) {
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Note: we must not detect failure as problem here, header can be trimmed. */
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device), device_alignment(device),
|
||||
buf, sizeof(LM_MAGIC), luks1_size) == (ssize_t)sizeof(LM_MAGIC) &&
|
||||
!memcmp(LM_MAGIC, buf, sizeof(LM_MAGIC))) {
|
||||
log_err(cd, _("Unable to convert header with LUKSMETA additional metadata."));
|
||||
r = -EBUSY;
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Convert LUKS1 -> LUKS2 */
|
||||
int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct luks2_hdr *hdr2)
|
||||
{
|
||||
@@ -493,6 +522,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
|
||||
return r;
|
||||
|
||||
luks1_size = LUKS_device_sectors(hdr1) << SECTOR_SHIFT;
|
||||
luks1_size = size_round_up(luks1_size, LUKS_ALIGN_KEYSLOTS);
|
||||
if (!luks1_size)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -501,10 +531,13 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (luksmeta_header_present(cd, luks1_size))
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg("Max size: %" PRIu64 ", LUKS1 (full) header size %zu , required shift: %zu",
|
||||
max_size, luks1_size, luks1_shift);
|
||||
if ((max_size - luks1_size) < luks1_shift) {
|
||||
log_err(cd, _("Unable to move keyslot materials. Not enough space\n"));
|
||||
log_err(cd, _("Unable to move keyslot area. Not enough space."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -543,8 +576,10 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
|
||||
// move keyslots 4k -> 32k offset
|
||||
buf_offset = 2 * LUKS2_HDR_16K_LEN;
|
||||
buf_size = luks1_size - LUKS_ALIGN_KEYSLOTS;
|
||||
if ((r = move_keyslot_areas(cd, 8 * SECTOR_SIZE, buf_offset, buf_size)) < 0)
|
||||
if ((r = move_keyslot_areas(cd, 8 * SECTOR_SIZE, buf_offset, buf_size)) < 0) {
|
||||
log_err(cd, _("Unable to move keyslot area."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Write JSON hdr2
|
||||
r = LUKS2_hdr_write(cd, hdr2);
|
||||
@@ -587,6 +622,7 @@ static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t
|
||||
return 0;
|
||||
|
||||
/* FIXME: should this go to validation code instead (aka invalid luks2 header if assigned to segment 0)? */
|
||||
/* FIXME: check all keyslots are assigned to segment id 0, and segments count == 1 */
|
||||
ks_key_size = LUKS2_get_keyslot_key_size(hdr, keyslot);
|
||||
if (ks_key_size < 0 || (int)key_size != LUKS2_get_keyslot_key_size(hdr, keyslot)) {
|
||||
log_dbg("Key length in keyslot %d is different from volume key length", keyslot);
|
||||
@@ -629,30 +665,48 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
if (!json_object_object_get_ex(jobj_digest, "type", &jobj2) ||
|
||||
strcmp(json_object_get_string(jobj2), "pbkdf2") ||
|
||||
json_object_object_length(jobj1) != 1) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - key slot digests are not LUKS1 compatible.\n"));
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - key slot digests are not LUKS1 compatible."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_size = r = LUKS2_get_volume_key_size(hdr2, 0);
|
||||
r = crypt_parse_name_and_mode(LUKS2_get_cipher(hdr2, CRYPT_DEFAULT_SEGMENT), cipher, NULL, cipher_mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (crypt_cipher_wrapped_key(cipher)) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - device uses wrapped key cipher %s."), cipher);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS2_tokens_count(hdr2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - LUKS2 header contains %u token(s)."), r);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS2_get_volume_key_size(hdr2, 0);
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
key_size = r;
|
||||
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INACTIVE)
|
||||
continue;
|
||||
|
||||
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INVALID) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is in invalid state.\n"), i);
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is in invalid state."), i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (i >= LUKS_NUMKEYS) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - slot %u (over maximum slots) is still active .\n"), i);
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - slot %u (over maximum slots) is still active."), i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!keyslot_LUKS1_compatible(hdr2, i, key_size)) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is not LUKS1 compatible.\n"), i);
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is not LUKS1 compatible."), i);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -674,8 +728,12 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
} else {
|
||||
if (LUKS2_find_area_gap(cd, hdr2, key_size, &offset, &area_length))
|
||||
return -EINVAL;
|
||||
/* FIXME: luks2 reload is required! */
|
||||
if (luks2_keyslot_alloc(cd, i, key_size))
|
||||
/*
|
||||
* We have to create placeholder luks2 keyslots in place of all
|
||||
* inactive keyslots. Otherwise we would allocate all
|
||||
* inactive luks1 keyslots over same binary keyslot area.
|
||||
*/
|
||||
if (placeholder_keyslot_alloc(cd, i, offset, area_length, key_size))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -784,8 +842,10 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
buf_offset = 2 * LUKS2_HDR_16K_LEN;
|
||||
buf_size = LUKS2_keyslots_size(hdr2->jobj);
|
||||
r = move_keyslot_areas(cd, buf_offset, 8 * SECTOR_SIZE, buf_size);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Unable to move keyslot area."));
|
||||
return r;
|
||||
}
|
||||
|
||||
crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO, 0,
|
||||
8 * SECTOR_SIZE, 8 * SECTOR_SIZE, NULL, NULL);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, token handling
|
||||
*
|
||||
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2017, Milan Broz. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Milan Broz. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -132,6 +132,7 @@ int LUKS2_token_create(struct crypt_device *cd,
|
||||
int commit)
|
||||
{
|
||||
const crypt_token_handler *h;
|
||||
const token_handler *th;
|
||||
json_object *jobj_tokens, *jobj_type, *jobj;
|
||||
enum json_tokener_error jerr;
|
||||
char num[16];
|
||||
@@ -169,14 +170,19 @@ int LUKS2_token_create(struct crypt_device *cd,
|
||||
|
||||
json_object_object_get_ex(jobj, "type", &jobj_type);
|
||||
if (is_builtin_candidate(json_object_get_string(jobj_type))) {
|
||||
log_dbg("%s is builtin token candidate", json_object_get_string(jobj_type));
|
||||
json_object_put(jobj);
|
||||
return -EINVAL;
|
||||
}
|
||||
th = LUKS2_token_handler_type_internal(cd, json_object_get_string(jobj_type));
|
||||
if (!th || !th->set) {
|
||||
log_dbg("%s is builtin token candidate with missing handler", json_object_get_string(jobj_type));
|
||||
json_object_put(jobj);
|
||||
return -EINVAL;
|
||||
}
|
||||
h = th->h;
|
||||
} else
|
||||
h = LUKS2_token_handler_type(cd, json_object_get_string(jobj_type));
|
||||
|
||||
h = LUKS2_token_handler_type(cd, json_object_get_string(jobj_type));
|
||||
if (h && h->validate && h->validate(cd, json)) {
|
||||
json_object_put(jobj);
|
||||
log_dbg("Token type %s validation failed.", h->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -257,7 +263,7 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
|
||||
|
||||
if (token == CRYPT_ANY_TOKEN) {
|
||||
if ((token = LUKS2_token_find_free(hdr)) < 0)
|
||||
log_err(cd, _("No free token slot\n"));
|
||||
log_err(cd, _("No free token slot."));
|
||||
}
|
||||
if (token < 0 || token >= LUKS2_TOKENS_MAX)
|
||||
return -EINVAL;
|
||||
@@ -265,14 +271,15 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
|
||||
|
||||
r = th->set(&jobj_token, params);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to create builtin token %s\n"), type);
|
||||
log_err(cd, _("Failed to create builtin token %s."), type);
|
||||
return r;
|
||||
}
|
||||
|
||||
// builtin tokens must produce valid json
|
||||
r = LUKS2_token_validate(hdr->jobj, jobj_token, "new");
|
||||
assert(!r);
|
||||
r = th->h->validate(cd, json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN));
|
||||
r = th->h->validate(cd, json_object_to_json_string_ext(jobj_token,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE));
|
||||
assert(!r);
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens);
|
||||
@@ -345,7 +352,7 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
|
||||
{
|
||||
const crypt_token_handler *h;
|
||||
json_object *jobj_token, *jobj_token_keyslots, *jobj;
|
||||
const char *num;
|
||||
const char *num = NULL;
|
||||
int i, r;
|
||||
|
||||
if (!(h = LUKS2_token_handler(cd, token)))
|
||||
@@ -361,14 +368,17 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
|
||||
|
||||
/* Try to open keyslot referenced in token */
|
||||
r = -EINVAL;
|
||||
for (i = 0; i < json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
|
||||
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
|
||||
jobj = json_object_array_get_idx(jobj_token_keyslots, i);
|
||||
num = json_object_get_string(jobj);
|
||||
log_dbg("Trying to open keyslot %s with token %d (type %s).", num, token, h->name);
|
||||
r = LUKS2_keyslot_open(cd, atoi(num), segment, buffer, buffer_len, vk);
|
||||
}
|
||||
|
||||
return r < 0 ? r : atoi(num);
|
||||
if (r >= 0 && num)
|
||||
return atoi(num);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
@@ -388,7 +398,8 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
return r;
|
||||
|
||||
r = LUKS2_keyslot_open_by_token(cd, hdr, token,
|
||||
name ? CRYPT_DEFAULT_SEGMENT : CRYPT_ANY_SEGMENT,
|
||||
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
|
||||
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
|
||||
buffer, buffer_len, &vk);
|
||||
|
||||
LUKS2_token_buffer_free(cd, token, buffer, buffer_len);
|
||||
@@ -399,11 +410,13 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
keyslot = r;
|
||||
|
||||
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
|
||||
r = crypt_volume_key_load_in_keyring(cd, vk);
|
||||
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
|
||||
|
||||
if (r >= 0 && name)
|
||||
r = LUKS2_activate(cd, name, vk, flags);
|
||||
|
||||
if (r < 0 && vk)
|
||||
crypt_drop_keyring_key(cd, vk->key_description);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
@@ -431,7 +444,8 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
|
||||
continue;
|
||||
|
||||
r = LUKS2_keyslot_open_by_token(cd, hdr, token,
|
||||
name ? CRYPT_DEFAULT_SEGMENT : CRYPT_ANY_SEGMENT,
|
||||
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
|
||||
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
|
||||
buffer, buffer_len, &vk);
|
||||
LUKS2_token_buffer_free(cd, token, buffer, buffer_len);
|
||||
if (r >= 0)
|
||||
@@ -441,11 +455,13 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
|
||||
keyslot = r;
|
||||
|
||||
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
|
||||
r = crypt_volume_key_load_in_keyring(cd, vk);
|
||||
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
|
||||
|
||||
if (r >= 0 && name)
|
||||
r = LUKS2_activate(cd, name, vk, flags);
|
||||
|
||||
if (r < 0 && vk)
|
||||
crypt_drop_keyring_key(cd, vk->key_description);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
@@ -460,7 +476,8 @@ void LUKS2_token_dump(struct crypt_device *cd, int token)
|
||||
if (h && h->dump) {
|
||||
jobj_token = LUKS2_get_token_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), token);
|
||||
if (jobj_token)
|
||||
h->dump(cd, json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN));
|
||||
h->dump(cd, json_object_to_json_string_ext(jobj_token,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,7 +490,8 @@ int LUKS2_token_json_get(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
if (!jobj_token)
|
||||
return -EINVAL;
|
||||
|
||||
*json = json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN);
|
||||
*json = json_object_to_json_string_ext(jobj_token,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -558,3 +576,36 @@ int LUKS2_token_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int keyslot, int token)
|
||||
{
|
||||
int i;
|
||||
json_object *jobj_token, *jobj_token_keyslots, *jobj;
|
||||
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
jobj_token = LUKS2_get_token_jobj(hdr, token);
|
||||
if (!jobj_token)
|
||||
return -ENOENT;
|
||||
|
||||
json_object_object_get_ex(jobj_token, "keyslots", &jobj_token_keyslots);
|
||||
|
||||
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots); i++) {
|
||||
jobj = json_object_array_get_idx(jobj_token_keyslots, i);
|
||||
if (keyslot == atoi(json_object_get_string(jobj)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_tokens_count(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj_tokens = LUKS2_get_tokens_jobj(hdr);
|
||||
if (!jobj_tokens)
|
||||
return -EINVAL;
|
||||
|
||||
return json_object_object_length(jobj_tokens);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, kernel keyring token
|
||||
*
|
||||
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2017, Ondrej Kozina. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Ondrej Kozina. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -31,6 +31,7 @@ static int keyring_open(struct crypt_device *cd,
|
||||
{
|
||||
json_object *jobj_token, *jobj_key;
|
||||
struct luks2_hdr *hdr;
|
||||
int r;
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
@@ -41,9 +42,14 @@ static int keyring_open(struct crypt_device *cd,
|
||||
|
||||
json_object_object_get_ex(jobj_token, "key_description", &jobj_key);
|
||||
|
||||
/* TODO: if r == -ENOKEY then instantiate the key? */
|
||||
if (keyring_get_passphrase(json_object_get_string(jobj_key), buffer, buffer_len))
|
||||
r = keyring_get_passphrase(json_object_get_string(jobj_key), buffer, buffer_len);
|
||||
if (r == -ENOTSUP) {
|
||||
log_dbg("Kernel keyring features disabled.");
|
||||
return -EINVAL;
|
||||
} else if (r < 0) {
|
||||
log_dbg("keyring_get_passphrase failed (error %d)", r);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -63,6 +69,11 @@ static int keyring_validate(struct crypt_device *cd __attribute__((unused)),
|
||||
return r;
|
||||
}
|
||||
|
||||
if (json_object_object_length(jobj_token) != 3) {
|
||||
log_dbg("Keyring token is expected to have exactly 3 fields.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_token, "key_description", &jobj_key)) {
|
||||
log_dbg("missing key_description field.");
|
||||
goto out;
|
||||
|
||||
10
lib/random.c
10
lib/random.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* cryptsetup kernel RNG access functions
|
||||
*
|
||||
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -167,13 +167,13 @@ int crypt_random_init(struct crypt_device *ctx)
|
||||
goto fail;
|
||||
|
||||
if (crypt_fips_mode())
|
||||
log_verbose(ctx, _("Running in FIPS mode.\n"));
|
||||
log_verbose(ctx, _("Running in FIPS mode."));
|
||||
|
||||
random_initialised = 1;
|
||||
return 0;
|
||||
fail:
|
||||
crypt_random_exit();
|
||||
log_err(ctx, _("Fatal error during RNG initialisation.\n"));
|
||||
log_err(ctx, _("Fatal error during RNG initialisation."));
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
@@ -210,12 +210,12 @@ int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int qualit
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_err(ctx, _("Unknown RNG quality requested.\n"));
|
||||
log_err(ctx, _("Unknown RNG quality requested."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (status)
|
||||
log_err(ctx, _("Error reading from RNG.\n"));
|
||||
log_err(ctx, _("Error reading from RNG."));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
1262
lib/setup.c
1262
lib/setup.c
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* TCRYPT (TrueCrypt-compatible) and VeraCrypt volume handling
|
||||
*
|
||||
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -31,25 +31,27 @@
|
||||
#include "internal.h"
|
||||
|
||||
/* TCRYPT PBKDF variants */
|
||||
static struct {
|
||||
static const struct {
|
||||
unsigned int legacy:1;
|
||||
unsigned int veracrypt:1;
|
||||
const char *name;
|
||||
const char *hash;
|
||||
unsigned int iterations;
|
||||
uint32_t veracrypt_pim_const;
|
||||
uint32_t veracrypt_pim_mult;
|
||||
} tcrypt_kdf[] = {
|
||||
{ 0, 0, "pbkdf2", "ripemd160", 2000 },
|
||||
{ 0, 0, "pbkdf2", "ripemd160", 1000 },
|
||||
{ 0, 0, "pbkdf2", "sha512", 1000 },
|
||||
{ 0, 0, "pbkdf2", "whirlpool", 1000 },
|
||||
{ 1, 0, "pbkdf2", "sha1", 2000 },
|
||||
{ 0, 1, "pbkdf2", "sha512", 500000 },
|
||||
{ 0, 1, "pbkdf2", "ripemd160", 655331 },
|
||||
{ 0, 1, "pbkdf2", "ripemd160", 327661 }, // boot only
|
||||
{ 0, 1, "pbkdf2", "whirlpool", 500000 },
|
||||
{ 0, 1, "pbkdf2", "sha256", 500000 }, // VeraCrypt 1.0f
|
||||
{ 0, 1, "pbkdf2", "sha256", 200000 }, // boot only
|
||||
{ 0, 0, NULL, NULL, 0 }
|
||||
{ 0, 0, "pbkdf2", "ripemd160", 2000, 0, 0 },
|
||||
{ 0, 0, "pbkdf2", "ripemd160", 1000, 0, 0 },
|
||||
{ 0, 0, "pbkdf2", "sha512", 1000, 0, 0 },
|
||||
{ 0, 0, "pbkdf2", "whirlpool", 1000, 0, 0 },
|
||||
{ 1, 0, "pbkdf2", "sha1", 2000, 0, 0 },
|
||||
{ 0, 1, "pbkdf2", "sha512", 500000, 15000, 1000 },
|
||||
{ 0, 1, "pbkdf2", "whirlpool", 500000, 15000, 1000 },
|
||||
{ 0, 1, "pbkdf2", "sha256", 500000, 15000, 1000 }, // VeraCrypt 1.0f
|
||||
{ 0, 1, "pbkdf2", "sha256", 200000, 0, 2048 }, // boot only
|
||||
{ 0, 1, "pbkdf2", "ripemd160", 655331, 15000, 1000 },
|
||||
{ 0, 1, "pbkdf2", "ripemd160", 327661, 0, 2048 }, // boot only
|
||||
{ 0, 0, NULL, NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
struct tcrypt_alg {
|
||||
@@ -350,7 +352,7 @@ static int TCRYPT_decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode,
|
||||
}
|
||||
|
||||
/*
|
||||
* For chanined ciphers and CBC mode we need "outer" decryption.
|
||||
* For chained ciphers and CBC mode we need "outer" decryption.
|
||||
* Backend doesn't provide this, so implement it here directly using ECB.
|
||||
*/
|
||||
static int TCRYPT_decrypt_cbci(struct tcrypt_algs *ciphers,
|
||||
@@ -457,23 +459,28 @@ static int TCRYPT_pool_keyfile(struct crypt_device *cd,
|
||||
unsigned char pool[TCRYPT_KEY_POOL_LEN],
|
||||
const char *keyfile)
|
||||
{
|
||||
unsigned char data[TCRYPT_KEYFILE_LEN];
|
||||
int i, j, fd, data_size;
|
||||
unsigned char *data;
|
||||
int i, j, fd, data_size, r = -EIO;
|
||||
uint32_t crc;
|
||||
|
||||
log_dbg("TCRYPT: using keyfile %s.", keyfile);
|
||||
|
||||
data = malloc(TCRYPT_KEYFILE_LEN);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
memset(data, 0, TCRYPT_KEYFILE_LEN);
|
||||
|
||||
fd = open(keyfile, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
log_err(cd, _("Failed to open key file.\n"));
|
||||
return -EIO;
|
||||
log_err(cd, _("Failed to open key file."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
data_size = read_buffer(fd, data, TCRYPT_KEYFILE_LEN);
|
||||
close(fd);
|
||||
if (data_size < 0) {
|
||||
log_err(cd, _("Error reading keyfile %s.\n"), keyfile);
|
||||
return -EIO;
|
||||
log_err(cd, _("Error reading keyfile %s."), keyfile);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0, crc = ~0U; i < data_size; i++) {
|
||||
@@ -484,11 +491,13 @@ static int TCRYPT_pool_keyfile(struct crypt_device *cd,
|
||||
pool[j++] += (unsigned char)(crc);
|
||||
j %= TCRYPT_KEY_POOL_LEN;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
crypt_memzero(&crc, sizeof(crc));
|
||||
crypt_memzero(data, TCRYPT_KEYFILE_LEN);
|
||||
free(data);
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int TCRYPT_init_hdr(struct crypt_device *cd,
|
||||
@@ -498,7 +507,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
|
||||
unsigned char pwd[TCRYPT_KEY_POOL_LEN] = {};
|
||||
size_t passphrase_size;
|
||||
char *key;
|
||||
unsigned int i, skipped = 0;
|
||||
unsigned int i, skipped = 0, iterations;
|
||||
int r = -EPERM;
|
||||
|
||||
if (posix_memalign((void*)&key, crypt_getpagesize(), TCRYPT_HDR_KEY_LEN))
|
||||
@@ -510,7 +519,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
|
||||
passphrase_size = params->passphrase_size;
|
||||
|
||||
if (params->passphrase_size > TCRYPT_KEY_POOL_LEN) {
|
||||
log_err(cd, _("Maximum TCRYPT passphrase length (%d) exceeded.\n"),
|
||||
log_err(cd, _("Maximum TCRYPT passphrase length (%d) exceeded."),
|
||||
TCRYPT_KEY_POOL_LEN);
|
||||
goto out;
|
||||
}
|
||||
@@ -532,23 +541,26 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
|
||||
if (!(params->flags & CRYPT_TCRYPT_VERA_MODES) && tcrypt_kdf[i].veracrypt)
|
||||
continue;
|
||||
if ((params->flags & CRYPT_TCRYPT_VERA_MODES) && params->veracrypt_pim) {
|
||||
/* Do not try TrueCrypt modes if we have PIM value */
|
||||
if (!tcrypt_kdf[i].veracrypt)
|
||||
continue;
|
||||
/* adjust iterations to given PIM cmdline parameter */
|
||||
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER)
|
||||
tcrypt_kdf[i].iterations = params->veracrypt_pim * 2048;
|
||||
else
|
||||
tcrypt_kdf[i].iterations = 15000 + (params->veracrypt_pim * 1000);
|
||||
}
|
||||
iterations = tcrypt_kdf[i].veracrypt_pim_const +
|
||||
(tcrypt_kdf[i].veracrypt_pim_mult * params->veracrypt_pim);
|
||||
} else
|
||||
iterations = tcrypt_kdf[i].iterations;
|
||||
|
||||
/* Derive header key */
|
||||
log_dbg("TCRYPT: trying KDF: %s-%s-%d.",
|
||||
tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations);
|
||||
log_dbg("TCRYPT: trying KDF: %s-%s-%d%s.",
|
||||
tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations,
|
||||
params->veracrypt_pim && tcrypt_kdf[i].veracrypt ? "-PIM" : "");
|
||||
r = crypt_pbkdf(tcrypt_kdf[i].name, tcrypt_kdf[i].hash,
|
||||
(char*)pwd, passphrase_size,
|
||||
hdr->salt, TCRYPT_HDR_SALT_LEN,
|
||||
key, TCRYPT_HDR_KEY_LEN,
|
||||
tcrypt_kdf[i].iterations, 0, 0);
|
||||
iterations, 0, 0);
|
||||
if (r < 0 && crypt_hash_size(tcrypt_kdf[i].hash) < 0) {
|
||||
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping.\n"),
|
||||
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping."),
|
||||
tcrypt_kdf[i].hash);
|
||||
continue;
|
||||
}
|
||||
@@ -566,9 +578,9 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
|
||||
}
|
||||
|
||||
if ((r < 0 && r != -EPERM && skipped && skipped == i) || r == -ENOTSUP) {
|
||||
log_err(cd, _("Required kernel crypto interface not available.\n"));
|
||||
log_err(cd, _("Required kernel crypto interface not available."));
|
||||
#ifdef ENABLE_AF_ALG
|
||||
log_err(cd, _("Ensure you have algif_skcipher kernel module loaded.\n"));
|
||||
log_err(cd, _("Ensure you have algif_skcipher kernel module loaded."));
|
||||
#endif
|
||||
}
|
||||
if (r < 0)
|
||||
@@ -625,7 +637,7 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
|
||||
if (devfd < 0) {
|
||||
log_err(cd, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Cannot open device %s."), device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -714,13 +726,13 @@ int TCRYPT_activate(struct crypt_device *cd,
|
||||
}
|
||||
|
||||
if (hdr->d.sector_size && hdr->d.sector_size != SECTOR_SIZE) {
|
||||
log_err(cd, _("Activation is not supported for %d sector size.\n"),
|
||||
log_err(cd, _("Activation is not supported for %d sector size."),
|
||||
hdr->d.sector_size);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (strstr(params->mode, "-tcrypt")) {
|
||||
log_err(cd, _("Kernel doesn't support activation for this TCRYPT legacy mode.\n"));
|
||||
log_err(cd, _("Kernel doesn't support activation for this TCRYPT legacy mode."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -754,7 +766,7 @@ int TCRYPT_activate(struct crypt_device *cd,
|
||||
dmd.u.crypt.offset, dmd.size);
|
||||
if (part_path) {
|
||||
if (!device_alloc(&part_device, part_path)) {
|
||||
log_verbose(cd, _("Activating TCRYPT system encryption for partition %s.\n"),
|
||||
log_verbose(cd, _("Activating TCRYPT system encryption for partition %s."),
|
||||
part_path);
|
||||
dmd.data_device = part_device;
|
||||
dmd.u.crypt.offset = 0;
|
||||
@@ -775,7 +787,7 @@ int TCRYPT_activate(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Frome here, key size for every cipher must be the same */
|
||||
/* From here, key size for every cipher must be the same */
|
||||
dmd.u.crypt.vk = crypt_alloc_volume_key(algs->cipher[0].key_size +
|
||||
algs->cipher[0].key_extra_size, NULL);
|
||||
if (!dmd.u.crypt.vk) {
|
||||
@@ -822,7 +834,7 @@ int TCRYPT_activate(struct crypt_device *cd,
|
||||
|
||||
if (r < 0 &&
|
||||
(dm_flags(DM_CRYPT, &dmc_flags) || ((dmc_flags & req_flags) != req_flags))) {
|
||||
log_err(cd, _("Kernel doesn't support TCRYPT compatible mapping.\n"));
|
||||
log_err(cd, _("Kernel doesn't support TCRYPT compatible mapping."));
|
||||
r = -ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* TCRYPT (TrueCrypt-compatible) header defitinion
|
||||
*
|
||||
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -19,11 +19,11 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
#ifndef _CRYPTSETUP_TCRYPT_H
|
||||
#define _CRYPTSETUP_TCRYPT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define TCRYPT_HDR_SALT_LEN 64
|
||||
#define TCRYPT_HDR_IV_LEN 16
|
||||
#define TCRYPT_HDR_LEN 448
|
||||
@@ -72,6 +72,8 @@ struct tcrypt_phdr {
|
||||
};
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct crypt_device;
|
||||
struct crypt_params_tcrypt;
|
||||
struct crypt_dm_active_device;
|
||||
struct volume_key;
|
||||
struct device;
|
||||
|
||||
380
lib/utils.c
380
lib/utils.c
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -22,14 +22,12 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -45,267 +43,21 @@ unsigned crypt_cpusonline(void)
|
||||
return r < 0 ? 1 : r;
|
||||
}
|
||||
|
||||
const char *uint64_to_str(char *buffer, size_t size, const uint64_t *val)
|
||||
uint64_t crypt_getphysmemory_kb(void)
|
||||
{
|
||||
int r = snprintf(buffer, size, "%" PRIu64, *val);
|
||||
if (r < 0) {
|
||||
log_dbg("Failed to convert integer to string.");
|
||||
*buffer = '\0';
|
||||
} else if ((size_t)r >= size) {
|
||||
log_dbg("Not enough space to store '%" PRIu64 "' to a string buffer.", *val);
|
||||
*buffer = '\0';
|
||||
}
|
||||
long pagesize, phys_pages;
|
||||
uint64_t phys_memory_kb;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
pagesize = sysconf(_SC_PAGESIZE);
|
||||
phys_pages = sysconf(_SC_PHYS_PAGES);
|
||||
|
||||
ssize_t read_buffer(int fd, void *buf, size_t count)
|
||||
{
|
||||
size_t read_size = 0;
|
||||
ssize_t r;
|
||||
if (pagesize < 0 || phys_pages < 0)
|
||||
return 0;
|
||||
|
||||
if (fd < 0 || !buf)
|
||||
return -EINVAL;
|
||||
phys_memory_kb = pagesize / 1024;
|
||||
phys_memory_kb *= phys_pages;
|
||||
|
||||
do {
|
||||
r = read(fd, buf, count - read_size);
|
||||
if (r == -1 && errno != EINTR)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return (ssize_t)read_size;
|
||||
if (r > 0) {
|
||||
read_size += (size_t)r;
|
||||
buf = (uint8_t*)buf + r;
|
||||
}
|
||||
} while (read_size != count);
|
||||
|
||||
return (ssize_t)count;
|
||||
}
|
||||
|
||||
ssize_t write_buffer(int fd, const void *buf, size_t count)
|
||||
{
|
||||
size_t write_size = 0;
|
||||
ssize_t w;
|
||||
|
||||
if (fd < 0 || !buf || !count)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
w = write(fd, buf, count - write_size);
|
||||
if (w < 0 && errno != EINTR)
|
||||
return w;
|
||||
if (w == 0)
|
||||
return (ssize_t)write_size;
|
||||
if (w > 0) {
|
||||
write_size += (size_t) w;
|
||||
buf = (const uint8_t*)buf + w;
|
||||
}
|
||||
} while (write_size != count);
|
||||
|
||||
return (ssize_t)write_size;
|
||||
}
|
||||
|
||||
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t count)
|
||||
{
|
||||
void *hangover_buf = NULL, *buf = NULL;
|
||||
size_t hangover, solid;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !orig_buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
hangover = count % bsize;
|
||||
solid = count - hangover;
|
||||
|
||||
if ((size_t)orig_buf & (alignment - 1)) {
|
||||
if (posix_memalign(&buf, alignment, count))
|
||||
return -1;
|
||||
memcpy(buf, orig_buf, count);
|
||||
} else
|
||||
buf = orig_buf;
|
||||
|
||||
if (solid) {
|
||||
r = write_buffer(fd, buf, solid);
|
||||
if (r < 0 || r != (ssize_t)solid)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hangover) {
|
||||
if (posix_memalign(&hangover_buf, alignment, bsize))
|
||||
goto out;
|
||||
|
||||
r = read_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0 || r < (ssize_t)hangover)
|
||||
goto out;
|
||||
|
||||
if (r < (ssize_t)bsize)
|
||||
bsize = r;
|
||||
|
||||
if (lseek(fd, -(off_t)bsize, SEEK_CUR) < 0)
|
||||
goto out;
|
||||
|
||||
memcpy(hangover_buf, (char*)buf + solid, hangover);
|
||||
|
||||
r = write_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0 || r < (ssize_t)hangover)
|
||||
goto out;
|
||||
}
|
||||
ret = count;
|
||||
out:
|
||||
free(hangover_buf);
|
||||
if (buf != orig_buf)
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t count)
|
||||
{
|
||||
void *hangover_buf = NULL, *buf = NULL;
|
||||
size_t hangover, solid;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !orig_buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
hangover = count % bsize;
|
||||
solid = count - hangover;
|
||||
|
||||
if ((size_t)orig_buf & (alignment - 1)) {
|
||||
if (posix_memalign(&buf, alignment, count))
|
||||
return -1;
|
||||
} else
|
||||
buf = orig_buf;
|
||||
|
||||
r = read_buffer(fd, buf, solid);
|
||||
if (r < 0 || r != (ssize_t)solid)
|
||||
goto out;
|
||||
|
||||
if (hangover) {
|
||||
if (posix_memalign(&hangover_buf, alignment, bsize))
|
||||
goto out;
|
||||
r = read_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0 || r < (ssize_t)hangover)
|
||||
goto out;
|
||||
|
||||
memcpy((char *)buf + solid, hangover_buf, hangover);
|
||||
}
|
||||
ret = count;
|
||||
out:
|
||||
free(hangover_buf);
|
||||
if (buf != orig_buf) {
|
||||
memcpy(orig_buf, buf, count);
|
||||
free(buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Combines llseek with blockwise write. write_blockwise can already deal with short writes
|
||||
* but we also need a function to deal with short writes at the start. But this information
|
||||
* is implicitly included in the read/write offset, which can not be set to non-aligned
|
||||
* boundaries. Hence, we combine llseek with write.
|
||||
*/
|
||||
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t count, off_t offset)
|
||||
{
|
||||
void *frontPadBuf = NULL;
|
||||
size_t frontHang, innerCount = 0;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
if (offset < 0)
|
||||
offset = lseek(fd, offset, SEEK_END);
|
||||
|
||||
if (offset < 0)
|
||||
return -1;
|
||||
|
||||
frontHang = offset % bsize;
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
if (frontHang) {
|
||||
if (posix_memalign(&frontPadBuf, alignment, bsize))
|
||||
return -1;
|
||||
|
||||
innerCount = bsize - frontHang;
|
||||
if (innerCount > count)
|
||||
innerCount = count;
|
||||
|
||||
r = read_buffer(fd, frontPadBuf, bsize);
|
||||
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
|
||||
goto out;
|
||||
|
||||
memcpy((char*)frontPadBuf + frontHang, buf, innerCount);
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
goto out;
|
||||
|
||||
r = write_buffer(fd, frontPadBuf, frontHang + innerCount);
|
||||
if (r < 0 || r != (ssize_t)(frontHang + innerCount))
|
||||
goto out;
|
||||
|
||||
buf = (char*)buf + innerCount;
|
||||
count -= innerCount;
|
||||
}
|
||||
|
||||
ret = count ? write_blockwise(fd, bsize, alignment, buf, count) : 0;
|
||||
if (ret >= 0)
|
||||
ret += innerCount;
|
||||
out:
|
||||
free(frontPadBuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t count, off_t offset)
|
||||
{
|
||||
void *frontPadBuf = NULL;
|
||||
size_t frontHang, innerCount = 0;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !buf || bsize <= 0)
|
||||
return -1;
|
||||
|
||||
if (offset < 0)
|
||||
offset = lseek(fd, offset, SEEK_END);
|
||||
|
||||
if (offset < 0)
|
||||
return -1;
|
||||
|
||||
frontHang = offset % bsize;
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
if (frontHang) {
|
||||
if (posix_memalign(&frontPadBuf, alignment, bsize))
|
||||
return -1;
|
||||
|
||||
innerCount = bsize - frontHang;
|
||||
if (innerCount > count)
|
||||
innerCount = count;
|
||||
|
||||
r = read_buffer(fd, frontPadBuf, bsize);
|
||||
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
|
||||
goto out;
|
||||
|
||||
memcpy(buf, (char*)frontPadBuf + frontHang, innerCount);
|
||||
|
||||
buf = (char*)buf + innerCount;
|
||||
count -= innerCount;
|
||||
}
|
||||
|
||||
ret = read_blockwise(fd, bsize, alignment, buf, count);
|
||||
if (ret >= 0)
|
||||
ret += innerCount;
|
||||
out:
|
||||
free(frontPadBuf);
|
||||
return ret;
|
||||
return phys_memory_kb;
|
||||
}
|
||||
|
||||
/* MEMLOCK */
|
||||
@@ -326,7 +78,7 @@ int crypt_memlock_inc(struct crypt_device *ctx)
|
||||
}
|
||||
errno = 0;
|
||||
if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
|
||||
log_err(ctx, _("Cannot get process priority.\n"));
|
||||
log_err(ctx, _("Cannot get process priority."));
|
||||
else
|
||||
if (setpriority(PRIO_PROCESS, 0, DEFAULT_PROCESS_PRIORITY))
|
||||
log_dbg("setpriority %d failed: %s",
|
||||
@@ -340,7 +92,7 @@ int crypt_memlock_dec(struct crypt_device *ctx)
|
||||
if (_memlock_count && (!--_memlock_count)) {
|
||||
log_dbg("Unlocking memory.");
|
||||
if (munlockall() == -1)
|
||||
log_err(ctx, _("Cannot unlock memory.\n"));
|
||||
log_err(ctx, _("Cannot unlock memory."));
|
||||
if (setpriority(PRIO_PROCESS, 0, _priority))
|
||||
log_dbg("setpriority %d failed: %s", _priority, strerror(errno));
|
||||
}
|
||||
@@ -356,14 +108,14 @@ int crypt_memlock_dec(struct crypt_device *ctx)
|
||||
* or when it reaches EOF before the requested number of bytes have been
|
||||
* discarded.
|
||||
*/
|
||||
static int keyfile_seek(int fd, size_t bytes)
|
||||
static int keyfile_seek(int fd, uint64_t bytes)
|
||||
{
|
||||
char tmp[BUFSIZ];
|
||||
size_t next_read;
|
||||
ssize_t bytes_r;
|
||||
off_t r;
|
||||
off64_t r;
|
||||
|
||||
r = lseek(fd, bytes, SEEK_CUR);
|
||||
r = lseek64(fd, bytes, SEEK_CUR);
|
||||
if (r > 0)
|
||||
return 0;
|
||||
if (r < 0 && errno != ESPIPE)
|
||||
@@ -371,13 +123,14 @@ static int keyfile_seek(int fd, size_t bytes)
|
||||
|
||||
while (bytes > 0) {
|
||||
/* figure out how much to read */
|
||||
next_read = bytes > sizeof(tmp) ? sizeof(tmp) : bytes;
|
||||
next_read = bytes > sizeof(tmp) ? sizeof(tmp) : (size_t)bytes;
|
||||
|
||||
bytes_r = read(fd, tmp, next_read);
|
||||
if (bytes_r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
crypt_memzero(tmp, sizeof(tmp));
|
||||
/* read error */
|
||||
return -1;
|
||||
}
|
||||
@@ -389,18 +142,20 @@ static int keyfile_seek(int fd, size_t bytes)
|
||||
bytes -= bytes_r;
|
||||
}
|
||||
|
||||
crypt_memzero(tmp, sizeof(tmp));
|
||||
return bytes == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile,
|
||||
char **key, size_t *key_size_read,
|
||||
size_t keyfile_offset, size_t keyfile_size_max,
|
||||
uint32_t flags)
|
||||
int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
|
||||
char **key, size_t *key_size_read,
|
||||
uint64_t keyfile_offset, size_t key_size,
|
||||
uint32_t flags)
|
||||
{
|
||||
int fd, regular_file, char_to_read = 0, char_read = 0, unlimited_read = 0;
|
||||
int r = -EINVAL, newline;
|
||||
char *pass = NULL;
|
||||
size_t buflen, i, file_read_size;
|
||||
size_t buflen, i;
|
||||
uint64_t file_read_size;
|
||||
struct stat st;
|
||||
|
||||
if (!key || !key_size_read)
|
||||
@@ -411,44 +166,44 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile,
|
||||
|
||||
fd = keyfile ? open(keyfile, O_RDONLY) : STDIN_FILENO;
|
||||
if (fd < 0) {
|
||||
log_err(cd, _("Failed to open key file.\n"));
|
||||
log_err(cd, _("Failed to open key file."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (isatty(fd)) {
|
||||
log_err(cd, _("Cannot read keyfile from a terminal.\n"));
|
||||
log_err(cd, _("Cannot read keyfile from a terminal."));
|
||||
r = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* If not requsted otherwise, we limit input to prevent memory exhaustion */
|
||||
if (keyfile_size_max == 0) {
|
||||
keyfile_size_max = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
|
||||
/* If not requested otherwise, we limit input to prevent memory exhaustion */
|
||||
if (key_size == 0) {
|
||||
key_size = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
|
||||
unlimited_read = 1;
|
||||
/* use 4k for buffer (page divisor but avoid huge pages) */
|
||||
buflen = 4096 - sizeof(struct safe_allocation);
|
||||
} else
|
||||
buflen = keyfile_size_max;
|
||||
buflen = key_size;
|
||||
|
||||
regular_file = 0;
|
||||
if (keyfile) {
|
||||
if (stat(keyfile, &st) < 0) {
|
||||
log_err(cd, _("Failed to stat key file.\n"));
|
||||
log_err(cd, _("Failed to stat key file."));
|
||||
goto out_err;
|
||||
}
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
regular_file = 1;
|
||||
file_read_size = (size_t)st.st_size;
|
||||
file_read_size = (uint64_t)st.st_size;
|
||||
|
||||
if (keyfile_offset > file_read_size) {
|
||||
log_err(cd, _("Cannot seek to requested keyfile offset.\n"));
|
||||
log_err(cd, _("Cannot seek to requested keyfile offset."));
|
||||
goto out_err;
|
||||
}
|
||||
file_read_size -= keyfile_offset;
|
||||
|
||||
/* known keyfile size, alloc it in one step */
|
||||
if (file_read_size >= keyfile_size_max)
|
||||
buflen = keyfile_size_max;
|
||||
if (file_read_size >= (uint64_t)key_size)
|
||||
buflen = key_size;
|
||||
else if (file_read_size)
|
||||
buflen = file_read_size;
|
||||
}
|
||||
@@ -456,22 +211,22 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile,
|
||||
|
||||
pass = crypt_safe_alloc(buflen);
|
||||
if (!pass) {
|
||||
log_err(cd, _("Out of memory while reading passphrase.\n"));
|
||||
log_err(cd, _("Out of memory while reading passphrase."));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Discard keyfile_offset bytes on input */
|
||||
if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) {
|
||||
log_err(cd, _("Cannot seek to requested keyfile offset.\n"));
|
||||
log_err(cd, _("Cannot seek to requested keyfile offset."));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
for (i = 0, newline = 0; i < keyfile_size_max; i += char_read) {
|
||||
for (i = 0, newline = 0; i < key_size; i += char_read) {
|
||||
if (i == buflen) {
|
||||
buflen += 4096;
|
||||
pass = crypt_safe_realloc(pass, buflen);
|
||||
if (!pass) {
|
||||
log_err(cd, _("Out of memory while reading passphrase.\n"));
|
||||
log_err(cd, _("Out of memory while reading passphrase."));
|
||||
r = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
@@ -485,13 +240,13 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile,
|
||||
*/
|
||||
char_to_read = 1;
|
||||
} else {
|
||||
/* char_to_read = min(keyfile_size_max - i, buflen - i) */
|
||||
char_to_read = keyfile_size_max < buflen ?
|
||||
keyfile_size_max - i : buflen - i;
|
||||
/* char_to_read = min(key_size - i, buflen - i) */
|
||||
char_to_read = key_size < buflen ?
|
||||
key_size - i : buflen - i;
|
||||
}
|
||||
char_read = read_buffer(fd, &pass[i], char_to_read);
|
||||
if (char_read < 0) {
|
||||
log_err(cd, _("Error reading passphrase.\n"));
|
||||
log_err(cd, _("Error reading passphrase."));
|
||||
r = -EPIPE;
|
||||
goto out_err;
|
||||
}
|
||||
@@ -508,19 +263,19 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile,
|
||||
|
||||
/* Fail if piped input dies reading nothing */
|
||||
if (!i && !regular_file && !newline) {
|
||||
log_dbg("Nothing read on input.");
|
||||
log_err(cd, _("Nothing to read on input."));
|
||||
r = -EPIPE;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Fail if we exceeded internal default (no specified size) */
|
||||
if (unlimited_read && i == keyfile_size_max) {
|
||||
log_err(cd, _("Maximum keyfile size exceeded.\n"));
|
||||
if (unlimited_read && i == key_size) {
|
||||
log_err(cd, _("Maximum keyfile size exceeded."));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!unlimited_read && i != keyfile_size_max) {
|
||||
log_err(cd, _("Cannot read requested amount of data.\n"));
|
||||
if (!unlimited_read && i != key_size) {
|
||||
log_err(cd, _("Cannot read requested amount of data."));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
@@ -535,3 +290,36 @@ out_err:
|
||||
crypt_safe_free(pass);
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile,
|
||||
char **key, size_t *key_size_read,
|
||||
size_t keyfile_offset, size_t keyfile_size_max,
|
||||
uint32_t flags)
|
||||
{
|
||||
return crypt_keyfile_device_read(cd, keyfile, key, key_size_read,
|
||||
keyfile_offset, keyfile_size_max, flags);
|
||||
}
|
||||
|
||||
int kernel_version(uint64_t *kversion)
|
||||
{
|
||||
struct utsname uts;
|
||||
uint16_t maj, min, patch, rel;
|
||||
int r = -EINVAL;
|
||||
|
||||
if (uname(&uts) < 0)
|
||||
return r;
|
||||
|
||||
if (sscanf(uts.release, "%" SCNu16 ".%" SCNu16 ".%" SCNu16 "-%" SCNu16,
|
||||
&maj, &min, &patch, &rel) == 4)
|
||||
r = 0;
|
||||
else if (sscanf(uts.release, "%" SCNu16 ".%" SCNu16 ".%" SCNu16,
|
||||
&maj, &min, &patch) == 3) {
|
||||
rel = 0;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (!r)
|
||||
*kversion = version(maj, min, patch, rel);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* libcryptsetup - cryptsetup library, cipher bechmark
|
||||
* libcryptsetup - cryptsetup library, cipher benchmark
|
||||
*
|
||||
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2017, Milan Broz
|
||||
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -281,33 +281,37 @@ static int benchmark_callback(uint32_t time_ms, void *usrptr)
|
||||
/*
|
||||
* Used in internal places to benchmark crypt_device context PBKDF.
|
||||
* Once requested parameters are benchmarked, iterations attribute is set,
|
||||
* and the benchamarked values can be reused.
|
||||
* Note that memory cost can be changed after benchark (if used).
|
||||
* and the benchmarked values can be reused.
|
||||
* Note that memory cost can be changed after benchmark (if used).
|
||||
* NOTE: You need to check that you are benchmarking for the same key size.
|
||||
*/
|
||||
int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
|
||||
struct crypt_pbkdf_type *pbkdf,
|
||||
size_t volume_key_size)
|
||||
{
|
||||
struct crypt_pbkdf_limits pbkdf_limits;
|
||||
double PBKDF2_tmp;
|
||||
uint32_t ms_tmp;
|
||||
int r = -EINVAL;
|
||||
|
||||
/* Already benchmarked */
|
||||
if (pbkdf->iterations) {
|
||||
log_dbg("Reusing PBKDF values.");
|
||||
return 0;
|
||||
}
|
||||
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
|
||||
log_err(cd, _("PBKDF benchmark disabled but iterations not set.\n"));
|
||||
if (pbkdf->iterations) {
|
||||
log_dbg("Reusing PBKDF values (no benchmark flag is set).");
|
||||
return 0;
|
||||
}
|
||||
log_err(cd, _("PBKDF benchmark disabled but iterations not set."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* For PBKDF2 run benchmark always. Also note it depends on volume_key_size! */
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
/*
|
||||
* For PBKDF2 it is enouch to run benchmark for only 1 second
|
||||
* and interpolate final iterarions value from it.
|
||||
* For PBKDF2 it is enough to run benchmark for only 1 second
|
||||
* and interpolate final iterations value from it.
|
||||
*/
|
||||
ms_tmp = pbkdf->time_ms;
|
||||
pbkdf->time_ms = 1000;
|
||||
@@ -318,7 +322,7 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
|
||||
volume_key_size, &benchmark_callback, pbkdf);
|
||||
pbkdf->time_ms = ms_tmp;
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"),
|
||||
log_err(cd, _("Not compatible PBKDF2 options (using hash algorithm %s)."),
|
||||
pbkdf->hash);
|
||||
return r;
|
||||
}
|
||||
@@ -326,13 +330,19 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
|
||||
PBKDF2_tmp = ((double)pbkdf->iterations * pbkdf->time_ms / 1000.);
|
||||
if (PBKDF2_tmp > (double)UINT32_MAX)
|
||||
return -EINVAL;
|
||||
pbkdf->iterations = at_least((uint32_t)PBKDF2_tmp, MIN_PBKDF2_ITERATIONS);
|
||||
pbkdf->iterations = at_least((uint32_t)PBKDF2_tmp, pbkdf_limits.min_iterations);
|
||||
} else {
|
||||
/* Already benchmarked */
|
||||
if (pbkdf->iterations) {
|
||||
log_dbg("Reusing PBKDF values.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = crypt_benchmark_pbkdf(cd, pbkdf, "foo", 3,
|
||||
"0123456789abcdef0123456789abcdef", 32,
|
||||
volume_key_size, &benchmark_callback, pbkdf);
|
||||
if (r < 0)
|
||||
log_err(cd, _("Not compatible PBKDF options.\n"));
|
||||
log_err(cd, _("Not compatible PBKDF options."));
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
309
lib/utils_blkid.c
Normal file
309
lib/utils_blkid.c
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* blkid probe utilities
|
||||
*
|
||||
* Copyright (C) 2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utils_blkid.h"
|
||||
#include "utils_io.h"
|
||||
|
||||
#ifdef HAVE_BLKID
|
||||
#include <blkid/blkid.h>
|
||||
/* make bad checksums flag optional */
|
||||
#ifndef BLKID_SUBLKS_BADCSUM
|
||||
#define BLKID_SUBLKS_BADCSUM 0
|
||||
#endif
|
||||
struct blkid_handle {
|
||||
int fd;
|
||||
blkid_probe pr;
|
||||
};
|
||||
#ifndef HAVE_BLKID_WIPE
|
||||
static size_t crypt_getpagesize(void)
|
||||
{
|
||||
long r = sysconf(_SC_PAGESIZE);
|
||||
return r <= 0 ? 4096 : (size_t)r;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void blk_set_chains_for_wipes(struct blkid_handle *h)
|
||||
{
|
||||
#ifdef HAVE_BLKID
|
||||
blkid_probe_enable_partitions(h->pr, 1);
|
||||
blkid_probe_set_partitions_flags(h->pr, 0
|
||||
#ifdef HAVE_BLKID_WIPE
|
||||
| BLKID_PARTS_MAGIC
|
||||
#endif
|
||||
);
|
||||
|
||||
blkid_probe_enable_superblocks(h->pr, 1);
|
||||
blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_LABEL |
|
||||
BLKID_SUBLKS_UUID |
|
||||
BLKID_SUBLKS_TYPE |
|
||||
BLKID_SUBLKS_USAGE |
|
||||
BLKID_SUBLKS_VERSION |
|
||||
BLKID_SUBLKS_MAGIC |
|
||||
BLKID_SUBLKS_BADCSUM);
|
||||
#endif
|
||||
}
|
||||
|
||||
void blk_set_chains_for_full_print(struct blkid_handle *h)
|
||||
{
|
||||
blk_set_chains_for_wipes(h);
|
||||
}
|
||||
|
||||
void blk_set_chains_for_fast_detection(struct blkid_handle *h)
|
||||
{
|
||||
#ifdef HAVE_BLKID
|
||||
blkid_probe_enable_partitions(h->pr, 1);
|
||||
blkid_probe_set_partitions_flags(h->pr, 0);
|
||||
|
||||
blkid_probe_enable_superblocks(h->pr, 1);
|
||||
blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_TYPE);
|
||||
#endif
|
||||
}
|
||||
|
||||
int blk_init_by_path(struct blkid_handle **h, const char *path)
|
||||
{
|
||||
int r = -ENOTSUP;
|
||||
#ifdef HAVE_BLKID
|
||||
struct blkid_handle *tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
tmp->fd = -1;
|
||||
|
||||
tmp->pr = blkid_new_probe_from_filename(path);
|
||||
if (!tmp->pr) {
|
||||
free(tmp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*h = tmp;
|
||||
|
||||
r = 0;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
int blk_init_by_fd(struct blkid_handle **h, int fd)
|
||||
{
|
||||
int r = -ENOTSUP;
|
||||
#ifdef HAVE_BLKID
|
||||
struct blkid_handle *tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
tmp->pr = blkid_new_probe();
|
||||
if (!tmp->pr) {
|
||||
free(tmp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (blkid_probe_set_device(tmp->pr, fd, 0, 0)) {
|
||||
blkid_free_probe(tmp->pr);
|
||||
free(tmp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tmp->fd = fd;
|
||||
|
||||
*h = tmp;
|
||||
|
||||
r = 0;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
int blk_superblocks_filter_luks(struct blkid_handle *h)
|
||||
{
|
||||
int r = -ENOTSUP;
|
||||
#ifdef HAVE_BLKID
|
||||
char luks[] = "crypto_LUKS";
|
||||
char *luks_filter[] = {
|
||||
luks,
|
||||
NULL
|
||||
};
|
||||
r = blkid_probe_filter_superblocks_type(h->pr, BLKID_FLTR_NOTIN, luks_filter);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
blk_probe_status blk_probe(struct blkid_handle *h)
|
||||
{
|
||||
blk_probe_status pr = PRB_FAIL;
|
||||
#ifdef HAVE_BLKID
|
||||
int r = blkid_do_probe(h->pr);
|
||||
|
||||
if (r == 0)
|
||||
pr = PRB_OK;
|
||||
else if (r == 1)
|
||||
pr = PRB_EMPTY;
|
||||
#endif
|
||||
return pr;
|
||||
}
|
||||
|
||||
blk_probe_status blk_safeprobe(struct blkid_handle *h)
|
||||
{
|
||||
int r = -1;
|
||||
#ifdef HAVE_BLKID
|
||||
r = blkid_do_safeprobe(h->pr);
|
||||
#endif
|
||||
switch (r) {
|
||||
case -2:
|
||||
return PRB_AMBIGUOUS;
|
||||
case 1:
|
||||
return PRB_EMPTY;
|
||||
case 0:
|
||||
return PRB_OK;
|
||||
default:
|
||||
return PRB_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int blk_is_partition(struct blkid_handle *h)
|
||||
{
|
||||
int r = 0;
|
||||
#ifdef HAVE_BLKID
|
||||
r = blkid_probe_has_value(h->pr, "PTTYPE");
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
int blk_is_superblock(struct blkid_handle *h)
|
||||
{
|
||||
int r = 0;
|
||||
#ifdef HAVE_BLKID
|
||||
r = blkid_probe_has_value(h->pr, "TYPE");
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
const char *blk_get_partition_type(struct blkid_handle *h)
|
||||
{
|
||||
const char *value = NULL;
|
||||
#ifdef HAVE_BLKID
|
||||
(void) blkid_probe_lookup_value(h->pr, "PTTYPE", &value, NULL);
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
const char *blk_get_superblock_type(struct blkid_handle *h)
|
||||
{
|
||||
const char *value = NULL;
|
||||
#ifdef HAVE_BLKID
|
||||
(void) blkid_probe_lookup_value(h->pr, "TYPE", &value, NULL);
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
void blk_free(struct blkid_handle *h)
|
||||
{
|
||||
#ifdef HAVE_BLKID
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
if (h->pr)
|
||||
blkid_free_probe(h->pr);
|
||||
|
||||
free(h);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_BLKID
|
||||
#ifndef HAVE_BLKID_WIPE
|
||||
static int blk_step_back(struct blkid_handle *h)
|
||||
{
|
||||
#ifdef HAVE_BLKID_STEP_BACK
|
||||
return blkid_probe_step_back(h->pr);
|
||||
#else
|
||||
blkid_reset_probe(h->pr);
|
||||
blkid_probe_set_device(h->pr, h->fd, 0, 0);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif /* not HAVE_BLKID_WIPE */
|
||||
#endif /* HAVE_BLKID */
|
||||
|
||||
int blk_do_wipe(struct blkid_handle *h)
|
||||
{
|
||||
#ifdef HAVE_BLKID
|
||||
#ifdef HAVE_BLKID_WIPE
|
||||
return blkid_do_wipe(h->pr, 0);
|
||||
#else
|
||||
const char *offset;
|
||||
off_t offset_val;
|
||||
void *buf;
|
||||
ssize_t ret;
|
||||
size_t alignment, len, bsize = blkid_probe_get_sectorsize(h->pr);
|
||||
|
||||
if (h->fd < 0 || !bsize)
|
||||
return -EINVAL;
|
||||
|
||||
if (blk_is_partition(h)) {
|
||||
if (blkid_probe_lookup_value(h->pr, "PTMAGIC_OFFSET", &offset, NULL))
|
||||
return -EINVAL;
|
||||
if (blkid_probe_lookup_value(h->pr, "PTMAGIC", NULL, &len))
|
||||
return -EINVAL;
|
||||
} else if (blk_is_superblock(h)) {
|
||||
if (blkid_probe_lookup_value(h->pr, "SBMAGIC_OFFSET", &offset, NULL))
|
||||
return -EINVAL;
|
||||
if (blkid_probe_lookup_value(h->pr, "SBMAGIC", NULL, &len))
|
||||
return -EINVAL;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
alignment = crypt_getpagesize();
|
||||
|
||||
if (posix_memalign(&buf, alignment, len))
|
||||
return -EINVAL;
|
||||
memset(buf, 0, len);
|
||||
|
||||
offset_val = strtoll(offset, NULL, 10);
|
||||
|
||||
/* TODO: missing crypt_wipe_fd() */
|
||||
ret = write_lseek_blockwise(h->fd, bsize, alignment, buf, len, offset_val);
|
||||
free(buf);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
|
||||
if ((size_t)ret == len) {
|
||||
blk_step_back(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
#endif
|
||||
#else /* HAVE_BLKID */
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
int blk_supported(void)
|
||||
{
|
||||
int r = 0;
|
||||
#ifdef HAVE_BLKID
|
||||
r = 1;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
62
lib/utils_blkid.h
Normal file
62
lib/utils_blkid.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* blkid probe utilities
|
||||
*
|
||||
* Copyright (C) 2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_BLKID_H
|
||||
#define _UTILS_BLKID_H
|
||||
|
||||
struct blkid_handle;
|
||||
|
||||
typedef enum { PRB_OK = 0, PRB_EMPTY, PRB_AMBIGUOUS, PRB_FAIL } blk_probe_status;
|
||||
|
||||
int blk_init_by_path(struct blkid_handle **h, const char *path);
|
||||
|
||||
void blk_free(struct blkid_handle *h);
|
||||
|
||||
/*
|
||||
* WARNING: This will reset file description offset as if
|
||||
* lseek(devfd, 0, SEEK_SET) was called!
|
||||
*/
|
||||
int blk_init_by_fd(struct blkid_handle **h, int fd);
|
||||
|
||||
void blk_set_chains_for_wipes(struct blkid_handle *h);
|
||||
|
||||
void blk_set_chains_for_full_print(struct blkid_handle *h);
|
||||
|
||||
void blk_set_chains_for_fast_detection(struct blkid_handle *h);
|
||||
|
||||
int blk_superblocks_filter_luks(struct blkid_handle *h);
|
||||
|
||||
blk_probe_status blk_safeprobe(struct blkid_handle *h);
|
||||
|
||||
blk_probe_status blk_probe(struct blkid_handle *h);
|
||||
|
||||
int blk_is_partition(struct blkid_handle *h);
|
||||
|
||||
int blk_is_superblock(struct blkid_handle *h);
|
||||
|
||||
const char *blk_get_partition_type(struct blkid_handle *h);
|
||||
|
||||
const char *blk_get_superblock_type(struct blkid_handle *h);
|
||||
|
||||
int blk_do_wipe(struct blkid_handle *h);
|
||||
|
||||
int blk_supported(void);
|
||||
|
||||
#endif
|
||||
@@ -2,8 +2,8 @@
|
||||
* utils_crypt - cipher utilities for cryptsetup
|
||||
*
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -37,7 +37,7 @@ int crypt_parse_name_and_mode(const char *s, char *cipher, int *key_nums,
|
||||
if (sscanf(s, "%" MAX_CIPHER_LEN_STR "[^-]-%" MAX_CIPHER_LEN_STR "s",
|
||||
cipher, cipher_mode) == 2) {
|
||||
if (!strcmp(cipher_mode, "plain"))
|
||||
strncpy(cipher_mode, "cbc-plain", 10);
|
||||
strcpy(cipher_mode, "cbc-plain");
|
||||
if (key_nums) {
|
||||
char *tmp = strchr(cipher, ':');
|
||||
*key_nums = tmp ? atoi(++tmp) : 1;
|
||||
@@ -49,16 +49,16 @@ int crypt_parse_name_and_mode(const char *s, char *cipher, int *key_nums,
|
||||
}
|
||||
|
||||
/* Short version for "empty" cipher */
|
||||
if (!strcmp(s, "null")) {
|
||||
strncpy(cipher, "cipher_null", MAX_CIPHER_LEN);
|
||||
strncpy(cipher_mode, "ecb", 9);
|
||||
if (!strcmp(s, "null") || !strcmp(s, "cipher_null")) {
|
||||
strcpy(cipher, "cipher_null");
|
||||
strcpy(cipher_mode, "ecb");
|
||||
if (key_nums)
|
||||
*key_nums = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sscanf(s, "%" MAX_CIPHER_LEN_STR "[^-]", cipher) == 1) {
|
||||
strncpy(cipher_mode, "cbc-plain", 10);
|
||||
strcpy(cipher_mode, "cbc-plain");
|
||||
if (key_nums)
|
||||
*key_nums = 1;
|
||||
return 0;
|
||||
@@ -105,6 +105,9 @@ int crypt_parse_integrity_mode(const char *s, char *integrity,
|
||||
!strcmp(s, "none")) {
|
||||
strncpy(integrity, s, MAX_CIPHER_LEN);
|
||||
ks = 0;
|
||||
} else if (!strcmp(s, "hmac-sha1")) {
|
||||
strncpy(integrity, "hmac(sha1)", MAX_CIPHER_LEN);
|
||||
ks = 20;
|
||||
} else if (!strcmp(s, "hmac-sha256")) {
|
||||
strncpy(integrity, "hmac(sha256)", MAX_CIPHER_LEN);
|
||||
ks = 32;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* utils_crypt - cipher utilities for cryptsetup
|
||||
*
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -48,8 +48,8 @@ struct device {
|
||||
|
||||
struct crypt_lock_handle *lh;
|
||||
|
||||
int o_direct:1;
|
||||
int init_done:1;
|
||||
unsigned int o_direct:1;
|
||||
unsigned int init_done:1;
|
||||
|
||||
/* cached values */
|
||||
size_t alignment;
|
||||
@@ -58,13 +58,19 @@ struct device {
|
||||
|
||||
static size_t device_fs_block_size_fd(int fd)
|
||||
{
|
||||
size_t page_size = crypt_getpagesize();
|
||||
|
||||
#ifdef HAVE_SYS_STATVFS_H
|
||||
struct statvfs buf;
|
||||
|
||||
if (!fstatvfs(fd, &buf) && buf.f_bsize)
|
||||
/*
|
||||
* NOTE: some filesystems (NFS) returns bogus blocksize (1MB).
|
||||
* Page-size io should always work and avoids increasing IO beyond aligned LUKS header.
|
||||
*/
|
||||
if (!fstatvfs(fd, &buf) && buf.f_bsize && buf.f_bsize <= page_size)
|
||||
return (size_t)buf.f_bsize;
|
||||
#endif
|
||||
return crypt_getpagesize();
|
||||
return page_size;
|
||||
}
|
||||
|
||||
static size_t device_block_size_fd(int fd, size_t *min_size)
|
||||
@@ -175,7 +181,7 @@ static int device_ready(struct device *device)
|
||||
}
|
||||
|
||||
if (devfd < 0) {
|
||||
log_err(NULL, _("Device %s doesn't exist or access denied.\n"),
|
||||
log_err(NULL, _("Device %s doesn't exist or access denied."),
|
||||
device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -246,7 +252,9 @@ static int device_open_internal(struct device *device, int flags)
|
||||
devfd = open(device_path(device), flags);
|
||||
|
||||
if (devfd < 0)
|
||||
log_dbg("Cannot open device %s.", device_path(device));
|
||||
log_dbg("Cannot open device %s%s.",
|
||||
device_path(device),
|
||||
(flags & O_ACCMODE) != O_RDONLY ? " for write" : "");
|
||||
|
||||
return devfd;
|
||||
}
|
||||
@@ -414,7 +422,9 @@ void device_topology_alignment(struct device *device,
|
||||
|
||||
temp_alignment = (unsigned long)min_io_size;
|
||||
|
||||
if (temp_alignment < (unsigned long)opt_io_size)
|
||||
/* Ignore bogus opt-io that could break alignment */
|
||||
if ((temp_alignment < (unsigned long)opt_io_size) &&
|
||||
!((unsigned long)opt_io_size % temp_alignment))
|
||||
temp_alignment = (unsigned long)opt_io_size;
|
||||
|
||||
/* If calculated alignment is multiple of default, keep default */
|
||||
@@ -498,7 +508,7 @@ int device_fallocate(struct device *device, uint64_t size)
|
||||
struct stat st;
|
||||
int devfd, r = -EINVAL;
|
||||
|
||||
devfd = open(device_path(device), O_WRONLY);
|
||||
devfd = open(device_path(device), O_RDWR);
|
||||
if(devfd == -1)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -563,7 +573,7 @@ static int device_info(struct crypt_device *cd,
|
||||
} else {
|
||||
/* If the device can be opened read-write, i.e. readonly is still 0, then
|
||||
* check whether BKROGET says that it is read-only. E.g. read-only loop
|
||||
* devices may be openend read-write but are read-only according to BLKROGET
|
||||
* devices may be opened read-write but are read-only according to BLKROGET
|
||||
*/
|
||||
if (real_readonly == 0 && (r = ioctl(fd, BLKROGET, &real_readonly)) < 0)
|
||||
goto out;
|
||||
@@ -587,13 +597,13 @@ out:
|
||||
break;
|
||||
case -EBUSY:
|
||||
log_err(cd, _("Cannot use device %s which is in use "
|
||||
"(already mapped or mounted).\n"), device->path);
|
||||
"(already mapped or mounted)."), device->path);
|
||||
break;
|
||||
case -EACCES:
|
||||
log_err(cd, _("Cannot use device %s, permission denied.\n"), device->path);
|
||||
log_err(cd, _("Cannot use device %s, permission denied."), device->path);
|
||||
break;
|
||||
default:
|
||||
log_err(cd, _("Cannot get info about device %s.\n"), device->path);
|
||||
log_err(cd, _("Cannot get info about device %s."), device->path);
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -616,7 +626,7 @@ static int device_internal_prepare(struct crypt_device *cd, struct device *devic
|
||||
|
||||
if (getuid() || geteuid()) {
|
||||
log_err(cd, _("Cannot use a loopback device, "
|
||||
"running as non-root user.\n"));
|
||||
"running as non-root user."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -626,7 +636,7 @@ static int device_internal_prepare(struct crypt_device *cd, struct device *devic
|
||||
loop_fd = crypt_loop_attach(&loop_device, device->path, 0, 1, &readonly);
|
||||
if (loop_fd == -1) {
|
||||
log_err(cd, _("Attaching loopback device failed "
|
||||
"(loop device with autoclear flag is required).\n"));
|
||||
"(loop device with autoclear flag is required)."));
|
||||
free(loop_device);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -671,7 +681,7 @@ int device_block_adjust(struct crypt_device *cd,
|
||||
return r;
|
||||
|
||||
if (device_offset >= real_size) {
|
||||
log_err(cd, _("Requested offset is beyond real size of device %s.\n"),
|
||||
log_err(cd, _("Requested offset is beyond real size of device %s."),
|
||||
device->path);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -679,7 +689,7 @@ int device_block_adjust(struct crypt_device *cd,
|
||||
if (size && !*size) {
|
||||
*size = real_size;
|
||||
if (!*size) {
|
||||
log_err(cd, _("Device %s has zero size.\n"), device->path);
|
||||
log_err(cd, _("Device %s has zero size."), device->path);
|
||||
return -ENOTBLK;
|
||||
}
|
||||
*size -= device_offset;
|
||||
@@ -690,7 +700,7 @@ int device_block_adjust(struct crypt_device *cd,
|
||||
log_dbg("Device %s: offset = %" PRIu64 " requested size = %" PRIu64
|
||||
", backing device size = %" PRIu64,
|
||||
device->path, device_offset, *size, real_size);
|
||||
log_err(cd, _("Device %s is too small.\n"), device->path);
|
||||
log_err(cd, _("Device %s is too small."), device->path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Metadata on-disk locking for processes serialization
|
||||
*
|
||||
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2017, Ondrej Kozina. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Ondrej Kozina. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -73,9 +73,11 @@ static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *b
|
||||
{
|
||||
int dirfd, lockdfd;
|
||||
|
||||
dirfd = open(dir, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
|
||||
dirfd = open(dir, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
if (dirfd < 0) {
|
||||
log_dbg("Failed to open directory '%s': (%d: %s).", dir, errno, strerror(errno));
|
||||
log_dbg("Failed to open directory %s: (%d: %s).", dir, errno, strerror(errno));
|
||||
if (errno == ENOTDIR || errno == ENOENT)
|
||||
log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (not a directory or missing)."), dir, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -89,8 +91,11 @@ static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *b
|
||||
log_dbg("Failed to create directory %s in %s (%d: %s).", base, dir, errno, strerror(errno));
|
||||
else
|
||||
lockdfd = openat(dirfd, base, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
|
||||
} else
|
||||
} else {
|
||||
log_dbg("Failed to open directory %s/%s: (%d: %s)", dir, base, errno, strerror(errno));
|
||||
if (errno == ENOTDIR || errno == ELOOP)
|
||||
log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (%s is not a directory)."), dir, base, base);
|
||||
}
|
||||
}
|
||||
|
||||
close(dirfd);
|
||||
@@ -172,8 +177,8 @@ static void release_lock_handle(struct crypt_lock_handle *h)
|
||||
if (S_ISBLK(h->mode) && /* was it block device */
|
||||
!flock(h->flock_fd, LOCK_EX | LOCK_NB) && /* lock to drop the file */
|
||||
!resource_by_devno(res, sizeof(res), h->devno, 1) && /* acquire lock resource name */
|
||||
!fstat(h->flock_fd, &buf_a) && /* read inode id refered by fd */
|
||||
!stat(res, &buf_b) && /* does path file stil exist? */
|
||||
!fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
|
||||
!stat(res, &buf_b) && /* does path file still exist? */
|
||||
same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
|
||||
/* coverity[toctou] */
|
||||
if (unlink(res)) /* yes? unlink the file */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Metadata on-disk locking for processes serialization
|
||||
*
|
||||
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2017, Ondrej Kozina. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Ondrej Kozina. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -86,7 +86,7 @@ struct crypt_dm_active_device {
|
||||
|
||||
/* struct crypt_active_device */
|
||||
uint64_t offset; /* offset in sectors */
|
||||
uint64_t iv_offset; /* IV initilisation sector */
|
||||
uint64_t iv_offset; /* IV initialisation sector */
|
||||
uint32_t tag_size; /* additional on-disk tag size */
|
||||
uint32_t sector_size; /* encryption sector size */
|
||||
} crypt;
|
||||
@@ -133,11 +133,13 @@ int dm_remove_device(struct crypt_device *cd, const char *name, uint32_t flags);
|
||||
int dm_status_device(struct crypt_device *cd, const char *name);
|
||||
int dm_status_suspended(struct crypt_device *cd, const char *name);
|
||||
int dm_status_verity_ok(struct crypt_device *cd, const char *name);
|
||||
int dm_status_integrity_failures(struct crypt_device *cd, const char *name, uint64_t *count);
|
||||
int dm_query_device(struct crypt_device *cd, const char *name,
|
||||
uint32_t get_flags, struct crypt_dm_active_device *dmd);
|
||||
int dm_create_device(struct crypt_device *cd, const char *name,
|
||||
const char *type, struct crypt_dm_active_device *dmd,
|
||||
int reload);
|
||||
int dm_suspend_device(struct crypt_device *cd, const char *name);
|
||||
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name);
|
||||
int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
|
||||
const struct volume_key *vk);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* FIPS mode utilities
|
||||
*
|
||||
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* FIPS mode utilities
|
||||
*
|
||||
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
298
lib/utils_io.c
Normal file
298
lib/utils_io.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* utils - miscellaneous I/O utilities for cryptsetup
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "utils_io.h"
|
||||
|
||||
static ssize_t _read_buffer(int fd, void *buf, size_t length, volatile int *quit)
|
||||
{
|
||||
size_t read_size = 0;
|
||||
ssize_t r;
|
||||
|
||||
if (fd < 0 || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
r = read(fd, buf, length - read_size);
|
||||
if (r == -1 && errno != EINTR)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
read_size += (size_t)r;
|
||||
buf = (uint8_t*)buf + r;
|
||||
}
|
||||
if (r == 0 || (quit && *quit))
|
||||
return (ssize_t)read_size;
|
||||
} while (read_size != length);
|
||||
|
||||
return (ssize_t)length;
|
||||
}
|
||||
|
||||
ssize_t read_buffer(int fd, void *buf, size_t length)
|
||||
{
|
||||
return _read_buffer(fd, buf, length, NULL);
|
||||
}
|
||||
|
||||
ssize_t read_buffer_intr(int fd, void *buf, size_t length, volatile int *quit)
|
||||
{
|
||||
return _read_buffer(fd, buf, length, quit);
|
||||
}
|
||||
|
||||
static ssize_t _write_buffer(int fd, const void *buf, size_t length, volatile int *quit)
|
||||
{
|
||||
size_t write_size = 0;
|
||||
ssize_t w;
|
||||
|
||||
if (fd < 0 || !buf || !length)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
w = write(fd, buf, length - write_size);
|
||||
if (w < 0 && errno != EINTR)
|
||||
return w;
|
||||
if (w > 0) {
|
||||
write_size += (size_t) w;
|
||||
buf = (const uint8_t*)buf + w;
|
||||
}
|
||||
if (w == 0 || (quit && *quit))
|
||||
return (ssize_t)write_size;
|
||||
} while (write_size != length);
|
||||
|
||||
return (ssize_t)write_size;
|
||||
}
|
||||
|
||||
ssize_t write_buffer(int fd, const void *buf, size_t length)
|
||||
{
|
||||
return _write_buffer(fd, buf, length, NULL);
|
||||
}
|
||||
|
||||
ssize_t write_buffer_intr(int fd, const void *buf, size_t length, volatile int *quit)
|
||||
{
|
||||
return _write_buffer(fd, buf, length, quit);
|
||||
}
|
||||
|
||||
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t length)
|
||||
{
|
||||
void *hangover_buf = NULL, *buf = NULL;
|
||||
size_t hangover, solid;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !orig_buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
hangover = length % bsize;
|
||||
solid = length - hangover;
|
||||
|
||||
if ((size_t)orig_buf & (alignment - 1)) {
|
||||
if (posix_memalign(&buf, alignment, length))
|
||||
return -1;
|
||||
memcpy(buf, orig_buf, length);
|
||||
} else
|
||||
buf = orig_buf;
|
||||
|
||||
if (solid) {
|
||||
r = write_buffer(fd, buf, solid);
|
||||
if (r < 0 || r != (ssize_t)solid)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hangover) {
|
||||
if (posix_memalign(&hangover_buf, alignment, bsize))
|
||||
goto out;
|
||||
memset(hangover_buf, 0, bsize);
|
||||
|
||||
r = read_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (lseek(fd, -(off_t)r, SEEK_CUR) < 0)
|
||||
goto out;
|
||||
|
||||
memcpy(hangover_buf, (char*)buf + solid, hangover);
|
||||
|
||||
r = write_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0 || r < (ssize_t)hangover)
|
||||
goto out;
|
||||
}
|
||||
ret = length;
|
||||
out:
|
||||
free(hangover_buf);
|
||||
if (buf != orig_buf)
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t length)
|
||||
{
|
||||
void *hangover_buf = NULL, *buf = NULL;
|
||||
size_t hangover, solid;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !orig_buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
hangover = length % bsize;
|
||||
solid = length - hangover;
|
||||
|
||||
if ((size_t)orig_buf & (alignment - 1)) {
|
||||
if (posix_memalign(&buf, alignment, length))
|
||||
return -1;
|
||||
} else
|
||||
buf = orig_buf;
|
||||
|
||||
r = read_buffer(fd, buf, solid);
|
||||
if (r < 0 || r != (ssize_t)solid)
|
||||
goto out;
|
||||
|
||||
if (hangover) {
|
||||
if (posix_memalign(&hangover_buf, alignment, bsize))
|
||||
goto out;
|
||||
r = read_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0 || r < (ssize_t)hangover)
|
||||
goto out;
|
||||
|
||||
memcpy((char *)buf + solid, hangover_buf, hangover);
|
||||
}
|
||||
ret = length;
|
||||
out:
|
||||
free(hangover_buf);
|
||||
if (buf != orig_buf) {
|
||||
memcpy(orig_buf, buf, length);
|
||||
free(buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Combines llseek with blockwise write. write_blockwise can already deal with short writes
|
||||
* but we also need a function to deal with short writes at the start. But this information
|
||||
* is implicitly included in the read/write offset, which can not be set to non-aligned
|
||||
* boundaries. Hence, we combine llseek with write.
|
||||
*/
|
||||
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t length, off_t offset)
|
||||
{
|
||||
void *frontPadBuf = NULL;
|
||||
size_t frontHang, innerCount = 0;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
if (offset < 0)
|
||||
offset = lseek(fd, offset, SEEK_END);
|
||||
|
||||
if (offset < 0)
|
||||
return -1;
|
||||
|
||||
frontHang = offset % bsize;
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
if (frontHang && length) {
|
||||
if (posix_memalign(&frontPadBuf, alignment, bsize))
|
||||
return -1;
|
||||
|
||||
innerCount = bsize - frontHang;
|
||||
if (innerCount > length)
|
||||
innerCount = length;
|
||||
|
||||
r = read_buffer(fd, frontPadBuf, bsize);
|
||||
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
|
||||
goto out;
|
||||
|
||||
memcpy((char*)frontPadBuf + frontHang, buf, innerCount);
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
goto out;
|
||||
|
||||
r = write_buffer(fd, frontPadBuf, bsize);
|
||||
if (r < 0 || r != (ssize_t)bsize)
|
||||
goto out;
|
||||
|
||||
buf = (char*)buf + innerCount;
|
||||
length -= innerCount;
|
||||
}
|
||||
|
||||
ret = length ? write_blockwise(fd, bsize, alignment, buf, length) : 0;
|
||||
if (ret >= 0)
|
||||
ret += innerCount;
|
||||
out:
|
||||
free(frontPadBuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t length, off_t offset)
|
||||
{
|
||||
void *frontPadBuf = NULL;
|
||||
size_t frontHang, innerCount = 0;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !buf || bsize <= 0)
|
||||
return -1;
|
||||
|
||||
if (offset < 0)
|
||||
offset = lseek(fd, offset, SEEK_END);
|
||||
|
||||
if (offset < 0)
|
||||
return -1;
|
||||
|
||||
frontHang = offset % bsize;
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
if (frontHang && length) {
|
||||
if (posix_memalign(&frontPadBuf, alignment, bsize))
|
||||
return -1;
|
||||
|
||||
innerCount = bsize - frontHang;
|
||||
if (innerCount > length)
|
||||
innerCount = length;
|
||||
|
||||
r = read_buffer(fd, frontPadBuf, bsize);
|
||||
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
|
||||
goto out;
|
||||
|
||||
memcpy(buf, (char*)frontPadBuf + frontHang, innerCount);
|
||||
|
||||
buf = (char*)buf + innerCount;
|
||||
length -= innerCount;
|
||||
}
|
||||
|
||||
ret = read_blockwise(fd, bsize, alignment, buf, length);
|
||||
if (ret >= 0)
|
||||
ret += innerCount;
|
||||
out:
|
||||
free(frontPadBuf);
|
||||
return ret;
|
||||
}
|
||||
42
lib/utils_io.h
Normal file
42
lib/utils_io.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* utils - miscellaneous I/O utilities for cryptsetup
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTSETUP_UTILS_IO_H
|
||||
#define _CRYPTSETUP_UTILS_IO_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
ssize_t read_buffer(int fd, void *buf, size_t length);
|
||||
ssize_t read_buffer_intr(int fd, void *buf, size_t length, volatile int *quit);
|
||||
ssize_t write_buffer(int fd, const void *buf, size_t length);
|
||||
ssize_t write_buffer_intr(int fd, const void *buf, size_t length, volatile int *quit);
|
||||
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t length);
|
||||
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t length);
|
||||
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t length, off_t offset);
|
||||
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t length, off_t offset);
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* kernel keyring utilities
|
||||
*
|
||||
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016, Ondrej Kozina. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Ondrej Kozina. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -31,7 +31,7 @@
|
||||
typedef int32_t key_serial_t;
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
#include "utils_crypt.h"
|
||||
#include "utils_keyring.h"
|
||||
|
||||
#ifdef KERNEL_KEYRING
|
||||
@@ -91,80 +91,16 @@ int keyring_add_key_in_thread_keyring(const char *key_desc, const void *key, siz
|
||||
#ifdef KERNEL_KEYRING
|
||||
key_serial_t kid;
|
||||
|
||||
log_dbg("Loading key %s (%zu bytes) in thread keyring", key_desc, key_size);
|
||||
|
||||
kid = add_key("logon", key_desc, key, key_size, KEY_SPEC_THREAD_KEYRING);
|
||||
if (kid < 0) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
log_dbg("add_key: the payload data is invalid.");
|
||||
break;
|
||||
case ENOMEM:
|
||||
log_dbg("add_key: insufficient memory to create a key.");
|
||||
break;
|
||||
case EDQUOT:
|
||||
log_dbg("add_key: quota would exceed.");
|
||||
break;
|
||||
}
|
||||
if (kid < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -EINVAL;
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef KERNEL_KEYRING
|
||||
static key_serial_t request_key_verbose(const char *type,
|
||||
const char *key_desc,
|
||||
const char *callout_info,
|
||||
key_serial_t keyring)
|
||||
{
|
||||
key_serial_t kid;
|
||||
|
||||
/*
|
||||
* Search for a key in this particular order (first found, first served):
|
||||
*
|
||||
* 1) thread keyring
|
||||
* 2) process keyring
|
||||
* 3) user keyring (if exists) or user session keyring (if exists)
|
||||
*/
|
||||
kid = request_key(type, key_desc, callout_info, keyring);
|
||||
if (kid < 0) {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
log_dbg("request_key: The keyring wasn't available for modification by the user.");
|
||||
break;
|
||||
case EINTR:
|
||||
log_dbg("request_key: The request was interrupted by a signal.");
|
||||
break;
|
||||
case EDQUOT:
|
||||
log_dbg("request_key: The key quota for this user would be exceeded by creating this key or linking it to the keyring.");
|
||||
break;
|
||||
case EKEYEXPIRED:
|
||||
log_dbg("request_key: An expired key was found, but no replacement could be obtained.");
|
||||
break;
|
||||
case EKEYREVOKED:
|
||||
log_dbg("request_key: A revoked key was found, but no replacement could be obtained.");
|
||||
break;
|
||||
case ENOKEY:
|
||||
log_dbg("request_key: No matching key was found.");
|
||||
break;
|
||||
/* NOTE following error codes are unreachable unless key generation is triggered */
|
||||
case EKEYREJECTED:
|
||||
log_dbg("request_key: The attempt to generate a new key was rejected.");
|
||||
break;
|
||||
case ENOMEM:
|
||||
log_dbg("request_key: Insufficient memory to create a key.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return kid;
|
||||
}
|
||||
#endif
|
||||
|
||||
int keyring_get_passphrase(const char *key_desc,
|
||||
char **passphrase,
|
||||
size_t *passphrase_len)
|
||||
@@ -176,10 +112,8 @@ int keyring_get_passphrase(const char *key_desc,
|
||||
char *buf = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
log_dbg("Looking for key described with '%s'.", key_desc);
|
||||
|
||||
do
|
||||
kid = request_key_verbose("user", key_desc, NULL, 0);
|
||||
kid = request_key("user", key_desc, NULL, 0);
|
||||
while (kid < 0 && errno == EINTR);
|
||||
|
||||
if (kid < 0)
|
||||
@@ -201,20 +135,6 @@ int keyring_get_passphrase(const char *key_desc,
|
||||
err = errno;
|
||||
crypt_memzero(buf, len);
|
||||
free(buf);
|
||||
switch (err) {
|
||||
case ENOKEY:
|
||||
log_dbg("keyctl_read: The key specified is invalid.");
|
||||
break;
|
||||
case EKEYEXPIRED:
|
||||
log_dbg("keyctl_read: The key specified has expired.");
|
||||
break;
|
||||
case EKEYREVOKED:
|
||||
log_dbg("keyctl_read: The key specified had been revoked.");
|
||||
break;
|
||||
case EACCES:
|
||||
log_dbg("keyctl_read: The key exists, but is not readable by the calling process.");
|
||||
break;
|
||||
}
|
||||
return -err;
|
||||
}
|
||||
|
||||
@@ -223,8 +143,7 @@ int keyring_get_passphrase(const char *key_desc,
|
||||
|
||||
return 0;
|
||||
#else
|
||||
log_dbg("Kernel keyring features disabled");
|
||||
return -EINVAL;
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -233,32 +152,15 @@ int keyring_revoke_and_unlink_key(const char *key_desc)
|
||||
#ifdef KERNEL_KEYRING
|
||||
key_serial_t kid;
|
||||
|
||||
log_dbg("requesting keyring key %s for removal", key_desc);
|
||||
|
||||
do
|
||||
kid = request_key_verbose("logon", key_desc, NULL, 0);
|
||||
kid = request_key("logon", key_desc, NULL, 0);
|
||||
while (kid < 0 && errno == EINTR);
|
||||
|
||||
if (kid < 0)
|
||||
return 0;
|
||||
|
||||
log_dbg("Revoking key %s", key_desc);
|
||||
|
||||
if (keyctl_revoke(kid)) {
|
||||
switch (errno) {
|
||||
case ENOKEY:
|
||||
log_dbg ("keyctl_revoke: The specified key does not exist.");
|
||||
break;
|
||||
case EKEYREVOKED:
|
||||
log_dbg("keyctl_revoke: The key has already been revoked.");
|
||||
break;
|
||||
case EACCES:
|
||||
log_dbg("keyctl_revoke: The name key exists, but is not writable by the calling process.");
|
||||
return -errno;
|
||||
default:
|
||||
log_dbg("keyctl_revoke: Unexpected errno: %d", errno);
|
||||
}
|
||||
}
|
||||
if (keyctl_revoke(kid))
|
||||
return -errno;
|
||||
|
||||
/*
|
||||
* best effort only. the key could have been linked
|
||||
@@ -271,6 +173,6 @@ int keyring_revoke_and_unlink_key(const char *key_desc)
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -EINVAL;
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* kernel keyring syscall wrappers
|
||||
*
|
||||
* Copyright (C) 2016, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016, Ondrej Kozina. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Ondrej Kozina. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -22,6 +22,8 @@
|
||||
#ifndef _UTILS_KEYRING
|
||||
#define _UTILS_KEYRING
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
int keyring_check(void);
|
||||
|
||||
int keyring_get_passphrase(const char *key_desc,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* loopback block device utilities
|
||||
*
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* loopback block device utilities
|
||||
*
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* utils_pbkdf - PBKDF ssettings for libcryptsetup
|
||||
*
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, Milan Broz
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -38,55 +38,99 @@ const struct crypt_pbkdf_type default_luks1 = {
|
||||
.time_ms = DEFAULT_LUKS1_ITER_TIME
|
||||
};
|
||||
|
||||
static uint32_t adjusted_phys_memory(void)
|
||||
{
|
||||
uint64_t memory_kb = crypt_getphysmemory_kb();
|
||||
|
||||
/* Ignore bogus value */
|
||||
if (memory_kb < (128 * 1024) || memory_kb > UINT32_MAX)
|
||||
return DEFAULT_LUKS2_MEMORY_KB;
|
||||
|
||||
/*
|
||||
* Never use more than half of physical memory.
|
||||
* OOM killer is too clever...
|
||||
*/
|
||||
memory_kb /= 2;
|
||||
|
||||
return memory_kb;
|
||||
}
|
||||
|
||||
/*
|
||||
* PBKDF configuration interface
|
||||
*/
|
||||
int verify_pbkdf_params(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf)
|
||||
{
|
||||
struct crypt_pbkdf_limits pbkdf_limits;
|
||||
const char *pbkdf_type;
|
||||
int r = 0;
|
||||
|
||||
if (!pbkdf->type || !pbkdf->hash || !pbkdf->time_ms)
|
||||
if (!pbkdf->type ||
|
||||
(!pbkdf->hash && !strcmp(pbkdf->type, "pbkdf2")))
|
||||
return -EINVAL;
|
||||
|
||||
if (!pbkdf->time_ms && !(pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK)) {
|
||||
log_err(cd, _("Requested PBKDF target time cannot be zero."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* TODO: initialise crypto and check the hash and pbkdf are both available */
|
||||
r = crypt_parse_pbkdf(pbkdf->type, &pbkdf_type);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Unknown PBKDF type %s.\n"), pbkdf->type);
|
||||
log_err(cd, _("Unknown PBKDF type %s."), pbkdf->type);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (crypt_get_type(cd) &&
|
||||
!strcmp(crypt_get_type(cd), CRYPT_LUKS1) &&
|
||||
strcmp(pbkdf_type, CRYPT_KDF_PBKDF2)) {
|
||||
log_err(cd, _("Requested PBKDF type is not supported for LUKS1.\n"));
|
||||
log_err(cd, _("Requested PBKDF type is not supported for LUKS1."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(pbkdf_type, CRYPT_KDF_PBKDF2)) {
|
||||
if (pbkdf->max_memory_kb || pbkdf->parallel_threads) {
|
||||
log_err(cd, _("PBKDF max memory or parallel threads must not be set with pbkdf2.\n"));
|
||||
log_err(cd, _("PBKDF max memory or parallel threads must not be set with pbkdf2."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK &&
|
||||
pbkdf->iterations < pbkdf_limits.min_iterations) {
|
||||
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u)."),
|
||||
pbkdf_type, pbkdf_limits.min_iterations);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pbkdf->max_memory_kb > MAX_PBKDF_MEMORY) {
|
||||
log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes).\n"),
|
||||
MAX_PBKDF_MEMORY);
|
||||
/* TODO: properly define minimal iterations and also minimal memory values */
|
||||
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
|
||||
if (pbkdf->iterations < pbkdf_limits.min_iterations) {
|
||||
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u)."),
|
||||
pbkdf_type, pbkdf_limits.min_iterations);
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (pbkdf->max_memory_kb < pbkdf_limits.min_memory) {
|
||||
log_err(cd, _("Forced memory cost is too low for %s (minimum is %u kilobytes)."),
|
||||
pbkdf_type, pbkdf_limits.min_memory);
|
||||
r = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pbkdf->max_memory_kb > pbkdf_limits.max_memory) {
|
||||
log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes)."),
|
||||
pbkdf_limits.max_memory);
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->max_memory_kb) {
|
||||
log_err(cd, _("Requested maximum PBKDF memory can not be zero.\n"));
|
||||
log_err(cd, _("Requested maximum PBKDF memory cannot be zero."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->parallel_threads) {
|
||||
log_err(cd, _("Requested PBKDF parallel threads can not be zero.\n"));
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->time_ms) {
|
||||
log_err(cd, _("Requested PBKDF target time can not be zero.\n"));
|
||||
log_err(cd, _("Requested PBKDF parallel threads cannot be zero."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
@@ -98,9 +142,10 @@ int init_pbkdf_type(struct crypt_device *cd,
|
||||
const char *dev_type)
|
||||
{
|
||||
struct crypt_pbkdf_type *cd_pbkdf = crypt_get_pbkdf(cd);
|
||||
struct crypt_pbkdf_limits pbkdf_limits;
|
||||
const char *hash, *type;
|
||||
unsigned cpus;
|
||||
uint32_t old_flags;
|
||||
uint32_t old_flags, memory_kb;
|
||||
int r;
|
||||
|
||||
if (!pbkdf && dev_type && !strcmp(dev_type, CRYPT_LUKS2))
|
||||
@@ -112,15 +157,19 @@ int init_pbkdf_type(struct crypt_device *cd,
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/*
|
||||
* Crypto backend may be not initialized here,
|
||||
* cannot check if algorithms are really available.
|
||||
* It will fail later anyway :-)
|
||||
*/
|
||||
type = strdup(pbkdf->type);
|
||||
hash = strdup(pbkdf->hash);
|
||||
hash = pbkdf->hash ? strdup(pbkdf->hash) : NULL;
|
||||
|
||||
if (!type || !hash) {
|
||||
if (!type || (!hash && pbkdf->hash)) {
|
||||
free(CONST_CAST(void*)type);
|
||||
free(CONST_CAST(void*)hash);
|
||||
return -ENOMEM;
|
||||
@@ -148,10 +197,10 @@ int init_pbkdf_type(struct crypt_device *cd,
|
||||
cd_pbkdf->max_memory_kb = pbkdf->max_memory_kb;
|
||||
cd_pbkdf->parallel_threads = pbkdf->parallel_threads;
|
||||
|
||||
if (cd_pbkdf->parallel_threads > MAX_PBKDF_THREADS) {
|
||||
if (cd_pbkdf->parallel_threads > pbkdf_limits.max_parallel) {
|
||||
log_dbg("Maximum PBKDF threads is %d (requested %d).",
|
||||
MAX_PBKDF_THREADS, cd_pbkdf->parallel_threads);
|
||||
cd_pbkdf->parallel_threads = MAX_PBKDF_THREADS;
|
||||
pbkdf_limits.max_parallel, cd_pbkdf->parallel_threads);
|
||||
cd_pbkdf->parallel_threads = pbkdf_limits.max_parallel;
|
||||
}
|
||||
|
||||
if (cd_pbkdf->parallel_threads) {
|
||||
@@ -164,6 +213,16 @@ int init_pbkdf_type(struct crypt_device *cd,
|
||||
}
|
||||
}
|
||||
|
||||
if (cd_pbkdf->max_memory_kb) {
|
||||
memory_kb = adjusted_phys_memory();
|
||||
if (cd_pbkdf->max_memory_kb > memory_kb) {
|
||||
log_dbg("Not enough physical memory detected, "
|
||||
"PBKDF max memory decreased from %dkB to %dkB.",
|
||||
cd_pbkdf->max_memory_kb, memory_kb);
|
||||
cd_pbkdf->max_memory_kb = memory_kb;
|
||||
}
|
||||
}
|
||||
|
||||
log_dbg("PBKDF %s, hash %s, time_ms %u (iterations %u), max_memory_kb %u, parallel_threads %u.",
|
||||
cd_pbkdf->type ?: "(none)", cd_pbkdf->hash ?: "(none)", cd_pbkdf->time_ms,
|
||||
cd_pbkdf->iterations, cd_pbkdf->max_memory_kb, cd_pbkdf->parallel_threads);
|
||||
@@ -194,6 +253,19 @@ const struct crypt_pbkdf_type *crypt_get_pbkdf_type(struct crypt_device *cd)
|
||||
return crypt_get_pbkdf(cd)->type ? crypt_get_pbkdf(cd) : NULL;
|
||||
}
|
||||
|
||||
const struct crypt_pbkdf_type *crypt_get_pbkdf_default(const char *type)
|
||||
{
|
||||
if (!type)
|
||||
return NULL;
|
||||
|
||||
if (!strcmp(type, CRYPT_LUKS1))
|
||||
return &default_luks1;
|
||||
else if (!strcmp(type, CRYPT_LUKS2))
|
||||
return &default_luks2;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_ms)
|
||||
{
|
||||
struct crypt_pbkdf_type *pbkdf;
|
||||
@@ -218,5 +290,5 @@ void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_m
|
||||
pbkdf->flags &= ~(CRYPT_PBKDF_NO_BENCHMARK);
|
||||
pbkdf->iterations = 0;
|
||||
|
||||
log_dbg("Iteration time set to %" PRIu64 " miliseconds.", iteration_time_ms);
|
||||
log_dbg("Iteration time set to %" PRIu64 " milliseconds.", iteration_time_ms);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user