2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2016 Google, Inc. All Rights Reserved.
5 # Functions for setting up and testing file encryption
8 # _require_scratch_encryption [-c CONTENTS_MODE] [-n FILENAMES_MODE]
9 # [-f POLICY_FLAGS] [-v POLICY_VERSION]
11 # Require encryption support on the scratch device.
13 # This checks for support for the default type of encryption policy (v1 with
14 # AES-256-XTS and AES-256-CTS). Options can be specified to also require
15 # support for a different type of encryption policy.
17 _require_scratch_encryption()
21 _require_xfs_io_command "set_encpolicy"
23 # The 'test_dummy_encryption' mount option interferes with trying to use
24 # encryption for real, even if we are just trying to get/set policies
25 # and never put any keys in the keyring. So skip the real encryption
26 # tests if the 'test_dummy_encryption' mount option was specified.
27 _exclude_scratch_mount_option "test_dummy_encryption"
29 # Make a filesystem on the scratch device with the encryption feature
30 # enabled. If this fails then probably the userspace tools (e.g.
31 # e2fsprogs or f2fs-tools) are too old to understand encryption.
32 if ! _scratch_mkfs_encrypted &>>$seqres.full; then
33 _notrun "$FSTYP userspace tools do not support encryption"
36 # Try to mount the filesystem. If this fails then either the kernel
37 # isn't aware of encryption, or the mkfs options were not compatible
38 # with encryption (e.g. ext4 with block size != PAGE_SIZE).
39 if ! _try_scratch_mount &>>$seqres.full; then
40 _notrun "kernel is unaware of $FSTYP encryption feature," \
41 "or mkfs options are not compatible with encryption"
44 # The kernel may be aware of encryption without supporting it. For
45 # example, for ext4 this is the case with kernels configured with
46 # CONFIG_EXT4_FS_ENCRYPTION=n. Detect support for encryption by trying
47 # to set an encryption policy. (For ext4 we could instead check for the
48 # presence of /sys/fs/ext4/features/encryption, but this is broken on
49 # some older kernels and is ext4-specific anyway.)
50 mkdir $SCRATCH_MNT/tmpdir
51 if _set_encpolicy $SCRATCH_MNT/tmpdir 2>&1 >>$seqres.full | \
52 egrep -q 'Inappropriate ioctl for device|Operation not supported'
54 _notrun "kernel does not support $FSTYP encryption"
56 rmdir $SCRATCH_MNT/tmpdir
58 # If required, check for support for the specific type of encryption
59 # policy required by the test.
61 _require_encryption_policy_support $SCRATCH_MNT "$@"
67 _require_encryption_policy_support()
71 local set_encpolicy_args=""
73 local policy_version=1
77 while getopts "c:n:f:v:" c; do
80 set_encpolicy_args+=" -$c $OPTARG"
83 set_encpolicy_args+=" -$c $OPTARG"
87 set_encpolicy_args+=" -$c $OPTARG"
88 policy_version=$OPTARG
91 _fail "Unrecognized option '$c'"
95 set_encpolicy_args=${set_encpolicy_args# }
97 echo "Checking whether kernel supports encryption policy: $set_encpolicy_args" \
100 if (( policy_flags & (FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 |
101 FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) )); then
103 _scratch_mkfs_stable_inodes_encrypted &>> $seqres.full
108 if (( policy_version > 1 )); then
109 _require_xfs_io_command "get_encpolicy" "-t"
110 local output=$(_get_encpolicy $dir -t)
111 if [ "$output" != "supported" ]; then
112 if [ "$output" = "unsupported" ]; then
113 _notrun "kernel does not support $FSTYP encryption v2 API"
115 _fail "Unexpected output from 'get_encpolicy -t': $output"
117 # Both the kernel and xfs_io support v2 encryption policies, and
118 # therefore also filesystem-level keys -- since that's the only
119 # way to provide keys for v2 policies.
120 local raw_key=$(_generate_raw_encryption_key)
121 local keyspec=$(_add_enckey $mnt "$raw_key" | awk '{print $NF}')
123 _require_command "$KEYCTL_PROG" keyctl
125 local keyspec=$(_generate_session_encryption_key)
127 if _set_encpolicy $dir $keyspec $set_encpolicy_args \
128 2>&1 >>$seqres.full | egrep -q 'Invalid argument'; then
129 _notrun "kernel does not support encryption policy: '$set_encpolicy_args'"
131 # fscrypt allows setting policies with modes it knows about, even
132 # without kernel crypto API support. E.g. a policy using Adiantum
133 # encryption can be set on a kernel without CONFIG_CRYPTO_ADIANTUM.
134 # But actually trying to use such an encrypted directory will fail.
135 # To reliably check for availability of both the contents and filenames
136 # encryption modes, try creating a nonempty file.
137 if ! echo foo > $dir/file; then
138 _notrun "encryption policy '$set_encpolicy_args' is unusable; probably missing kernel crypto API support"
140 if (( policy_version <= 1 )); then
141 $KEYCTL_PROG clear @s
146 _scratch_mkfs_encrypted()
150 _scratch_mkfs -O encrypt
153 # erase the UBI volume; reformated automatically on next mount
154 $UBIUPDATEVOL_PROG ${SCRATCH_DEV} -t
157 _notrun "No encryption support for $FSTYP"
162 _scratch_mkfs_sized_encrypted()
166 MKFS_OPTIONS="$MKFS_OPTIONS -O encrypt" _scratch_mkfs_sized $*
169 _notrun "Filesystem $FSTYP not supported in _scratch_mkfs_sized_encrypted"
174 # Like _scratch_mkfs_encrypted(), but add -O stable_inodes if applicable for the
175 # filesystem type. This is necessary for using encryption policies that include
176 # the inode number in the IVs, e.g. policies with the IV_INO_LBLK_64 flag set.
177 _scratch_mkfs_stable_inodes_encrypted()
181 if ! _scratch_mkfs -O encrypt -O stable_inodes; then
182 _notrun "-O stable_inodes is not supported"
186 _scratch_mkfs_encrypted
191 # For some tests it's helpful to always use the same key so that the test's
192 # output is always the same. For this purpose the following key can be used:
195 TEST_RAW_KEY+="\\x$(printf "%02x" $i)"
197 # Key descriptor: arbitrary value
198 TEST_KEY_DESCRIPTOR="0000111122223333"
199 # Key identifier: HKDF-SHA512(key=$TEST_RAW_KEY, salt="", info="fscrypt\0\x01")
200 TEST_KEY_IDENTIFIER="69b2f6edeee720cce0577937eb8a6751"
202 # Give the invoking shell a new session keyring. This makes any keys we add to
203 # the session keyring scoped to the lifetime of the test script.
204 _new_session_keyring()
206 $KEYCTL_PROG new_session >>$seqres.full
209 # Generate a key descriptor (16 character hex string)
210 _generate_key_descriptor()
214 for ((i = 0; i < 8; i++)); do
215 keydesc="${keydesc}$(printf "%02x" $(( $RANDOM % 256 )))"
220 # Generate a raw encryption key, but don't add it to any keyring yet.
221 _generate_raw_encryption_key()
225 for ((i = 0; i < 64; i++)); do
226 raw="${raw}\\x$(printf "%02x" $(( $RANDOM % 256 )))"
231 # Serialize an integer into a CPU-endian bytestring of the given length, and
232 # print it as a string where each byte is hex-escaped. For example,
233 # `_num_to_hex 1000 4` == "\xe8\x03\x00\x00" if the CPU is little endian.
239 local big_endian=$(echo -ne '\x11' | od -tx2 | head -1 | \
240 cut -f2 -d' ' | cut -c1)
242 if (( big_endian )); then
243 for (( i = 0; i < nbytes; i++ )); do
244 printf '\\x%02x' $(((value >> (8*(nbytes-1-i))) & 0xff))
247 for (( i = 0; i < nbytes; i++ )); do
248 printf '\\x%02x' $(((value >> (8*i)) & 0xff))
253 # Add the specified raw encryption key to the session keyring, using the
254 # specified key descriptor.
255 _add_session_encryption_key()
261 # Add the key to the session keyring. The required structure is:
263 # #define FSCRYPT_MAX_KEY_SIZE 64
264 # struct fscrypt_key {
266 # __u8 raw[FSCRYPT_MAX_KEY_SIZE];
270 # The kernel ignores 'mode' but requires that 'size' be 64.
272 # Keys are named $FSTYP:KEYDESC where KEYDESC is the 16-character key
273 # descriptor hex string. Newer kernels (ext4 4.8 and later, f2fs 4.6
274 # and later) also allow the common key prefix "fscrypt:" in addition to
275 # their filesystem-specific key prefix ("ext4:", "f2fs:"). It would be
276 # nice to use the common key prefix, but for now use the filesystem-
277 # specific prefix to make it possible to test older kernels...
279 local mode=$(_num_to_hex 0 4)
280 local size=$(_num_to_hex 64 4)
281 echo -n -e "${mode}${raw}${size}" |
282 $KEYCTL_PROG padd logon $FSTYP:$keydesc @s >>$seqres.full
286 # Generate a random encryption key, add it to the session keyring, and print out
287 # the resulting key descriptor (example: "8bf798e1a494e1ec"). Requires the
288 # keyctl program. It's assumed the caller has already set up a test-scoped
289 # session keyring using _new_session_keyring.
291 _generate_session_encryption_key()
293 local keydesc=$(_generate_key_descriptor)
294 local raw=$(_generate_raw_encryption_key)
296 _add_session_encryption_key $keydesc $raw
301 # Unlink an encryption key from the session keyring, given its key descriptor.
302 _unlink_session_encryption_key()
305 local keyid=$($KEYCTL_PROG search @s logon $FSTYP:$keydesc)
306 $KEYCTL_PROG unlink $keyid >>$seqres.full
309 # Revoke an encryption key from the session keyring, given its key descriptor.
310 _revoke_session_encryption_key()
313 local keyid=$($KEYCTL_PROG search @s logon $FSTYP:$keydesc)
314 $KEYCTL_PROG revoke $keyid >>$seqres.full
317 # Set an encryption policy on the specified directory.
323 $XFS_IO_PROG -c "set_encpolicy $*" "$dir"
326 _user_do_set_encpolicy()
331 _user_do "$XFS_IO_PROG -c \"set_encpolicy $*\" \"$dir\""
334 # Display the specified file or directory's encryption policy.
340 $XFS_IO_PROG -c "get_encpolicy $*" "$file"
343 _user_do_get_encpolicy()
348 _user_do "$XFS_IO_PROG -c \"get_encpolicy $*\" \"$file\""
351 # Add an encryption key to the given filesystem.
358 echo -ne "$raw_key" | $XFS_IO_PROG -c "add_enckey $*" "$mnt"
361 _user_do_add_enckey()
367 _user_do "echo -ne \"$raw_key\" | $XFS_IO_PROG -c \"add_enckey $*\" \"$mnt\""
370 # Remove the given encryption key from the given filesystem.
377 $XFS_IO_PROG -c "rm_enckey $* $keyspec" "$mnt"
386 _user_do "$XFS_IO_PROG -c \"rm_enckey $* $keyspec\" \"$mnt\""
389 # Get the status of the given encryption key on the given filesystem.
396 $XFS_IO_PROG -c "enckey_status $* $keyspec" "$mnt"
399 _user_do_enckey_status()
405 _user_do "$XFS_IO_PROG -c \"enckey_status $* $keyspec\" \"$mnt\""
408 # Require support for adding a key to a filesystem's fscrypt keyring via an
409 # "fscrypt-provisioning" keyring key.
410 _require_add_enckey_by_key_id()
415 _require_xfs_io_command "add_enckey" "-k"
418 if $XFS_IO_PROG -c "add_enckey -k 12345" "$mnt" \
419 |& grep -q 'Invalid argument'; then
420 _notrun "Kernel doesn't support key_id parameter to FS_IOC_ADD_ENCRYPTION_KEY"
424 # Add a key of type "fscrypt-provisioning" to the session keyring and print the
426 _add_fscrypt_provisioning_key()
432 # The format of the key payload must be:
434 # struct fscrypt_provisioning_key_payload {
440 local type_hex=$(_num_to_hex $type 4)
441 local reserved=$(_num_to_hex 0 4)
442 echo -n -e "${type_hex}${reserved}${raw}" |
443 $KEYCTL_PROG padd fscrypt-provisioning "$desc" @s
446 # Retrieve the encryption nonce of the given inode as a hex string. The nonce
447 # was randomly generated by the filesystem and isn't exposed directly to
448 # userspace. But it can be read using the filesystem's debugging tools.
449 _get_encryption_nonce()
456 # Use debugfs to dump the special xattr named "c", which is the
457 # file's fscrypt_context. This produces a line like:
459 # c (28) = 01 01 04 02 00 00 00 00 00 00 00 00 ef bd 18 76 5d f6 41 4e c0 a2 cd 5f 91 29 7e 12
461 # Then filter it to get just the 16-byte 'nonce' field at the end:
463 # efbd18765df6414ec0a2cd5f91297e12
465 $DEBUGFS_PROG $device -R "ea_get <$inode> c" 2>>$seqres.full \
466 | grep '^c ' | sed 's/^.*=//' | tr -d ' \n' | tail -c 32
469 # dump.f2fs prints the fscrypt_context like:
471 # xattr: e_name_index:9 e_name:c e_name_len:1 e_value_size:28 e_value:
473 # contents_encryption_mode: 0x1
474 # filenames_encryption_mode: 0x4
476 # master_key_descriptor: 0000000000000000
477 # nonce: EFBD18765DF6414EC0A2CD5F91297E12
479 # Also support the case where the whole xattr is printed as hex,
480 # as is the case for fscrypt_context_v2.
482 # xattr: e_name_index:9 e_name:c e_name_len:1 e_value_size:40 e_value:
483 # 020104020000000033809BFEBE68A4AD264079B30861DD5E6B9E72D07523C58794ACF52534BAA756
485 $DUMP_F2FS_PROG -i $inode $device | awk '
486 /\<e_name:c\>/ { found = 1 }
487 (/^nonce:/ || /^[[:xdigit:]]+$/) && found {
488 print substr($0, length($0) - 31, 32);
493 _fail "_get_encryption_nonce() isn't implemented on $FSTYP"
498 # Require support for _get_encryption_nonce()
499 _require_get_encryption_nonce_support()
501 echo "Checking for _get_encryption_nonce() support for $FSTYP" >> $seqres.full
504 _require_command "$DEBUGFS_PROG" debugfs
507 _require_command "$DUMP_F2FS_PROG" dump.f2fs
508 # For fscrypt_context_v2, we actually need a f2fs-tools version
509 # that has the patch "f2fs-tools: improve xattr value printing"
510 # (https://sourceforge.net/p/linux-f2fs/mailman/message/36648640/).
511 # Otherwise the xattr is incorrectly parsed as v1. But just let
512 # the test fail in that case, as it was an f2fs-tools bug...
515 _notrun "_get_encryption_nonce() isn't implemented on $FSTYP"
520 # Retrieve the encrypted filename stored on-disk for the given file.
521 # The name is printed to stdout in binary.
522 _get_ciphertext_filename()
530 # Extract the filename from the debugfs output line like:
532 # 131075 100644 (1) 0 0 0 22-Apr-2019 16:54 \xa2\x85\xb0z\x13\xe9\x09\x86R\xed\xdc\xce\xad\x14d\x19
534 # Bytes are shown either literally or as \xHH-style escape
535 # sequences; we have to decode the escaped bytes here.
537 $DEBUGFS_PROG $device -R "ls -l -r <$dir_inode>" \
538 2>>$seqres.full | perl -ne '
539 next if not /^\s*'$inode'\s+/;
542 s/\\x([[:xdigit:]]{2})/chr hex $1/eg;
546 # Extract the filename from the dump.f2fs output line like:
548 # i_name [UpkzIPuts9by1oDmE+Ivfw]
550 # The name is shown base64-encoded; we have to decode it here.
552 $DUMP_F2FS_PROG $device -i $inode | perl -ne '
553 next if not /^i_name\s+\[([A-Za-z0-9+,]+)\]/;
555 my @chars = split //, $1;
558 my $table = join "", (A..Z, a..z, 0..9, "+", ",");
560 $ac += index($table, $_) << $bits;
563 print chr($ac & 0xff);
569 print STDERR "Invalid base64-encoded string!\n";
573 _fail "_get_ciphertext_filename() isn't implemented on $FSTYP"
578 # Require support for _get_ciphertext_filename().
579 _require_get_ciphertext_filename_support()
581 echo "Checking for _get_ciphertext_filename() support for $FSTYP" >> $seqres.full
584 # Verify that the "ls -l -r" debugfs command is supported and
585 # that it hex-encodes non-ASCII characters, rather than using an
586 # ambiguous escaping method. This requires e2fsprogs v1.45.1 or
587 # later; or more specifically, a version that has the commit
588 # "debugfs: avoid ambiguity when printing filenames".
589 _require_command "$DEBUGFS_PROG" debugfs
591 touch $SCRATCH_MNT/$'\xc1'
593 if ! $DEBUGFS_PROG $SCRATCH_DEV -R "ls -l -r /" 2>&1 \
594 | tee -a $seqres.full | grep -E -q '\s+\\xc1\s*$'; then
595 _notrun "debugfs (e2fsprogs) is too old; doesn't support showing unambiguous on-disk filenames"
599 # Verify that dump.f2fs shows encrypted filenames in full. This
600 # requires f2fs-tools v1.13.0 or later; or more specifically, a
601 # version that has the commit
602 # "f2fs-tools: improve filename printing".
604 _require_command "$DUMP_F2FS_PROG" dump.f2fs
605 _require_command "$KEYCTL_PROG" keyctl
609 local keydesc=$(_generate_session_encryption_key)
610 local dir=$SCRATCH_MNT/test.${FUNCNAME[0]}
611 local file=$dir/$(perl -e 'print "A" x 255')
613 _set_encpolicy $dir $keydesc
615 local inode=$(stat -c %i $file)
618 $KEYCTL_PROG clear @s
620 # 255-character filename should result in 340 base64 characters.
621 if ! $DUMP_F2FS_PROG -i $inode $SCRATCH_DEV \
622 | grep -E -q '^i_name[[:space:]]+\[[A-Za-z0-9+,]{340}\]'; then
623 _notrun "dump.f2fs (f2fs-tools) is too old; doesn't support showing unambiguous on-disk filenames"
627 _notrun "_get_ciphertext_filename() isn't implemented on $FSTYP"
632 # Get an encrypted file's list of on-disk blocks as a comma-separated list of
633 # block offsets from the start of the device. "Blocks" are 512 bytes each here.
634 _get_ciphertext_block_list()
639 $XFS_IO_PROG -c fiemap $file | perl -ne '
640 next if not /^\s*\d+: \[\d+\.\.\d+\]: (\d+)\.\.(\d+)/;
641 print $_ . "," foreach $1..$2;' | sed 's/,$//'
644 # Dump a block list that was previously saved by _get_ciphertext_block_list().
645 _dump_ciphertext_blocks()
651 for block in $(tr ',' ' ' <<< $blocklist); do
652 dd if=$device bs=512 count=1 skip=$block status=none
656 _do_verify_ciphertext_for_encryption_policy()
658 local contents_encryption_mode=$1
659 local filenames_encryption_mode=$2
660 local policy_flags=$3
661 local set_encpolicy_args=$4
664 local crypt_contents_cmd="$here/src/fscrypt-crypt-util $7"
665 local crypt_filename_cmd="$here/src/fscrypt-crypt-util $8"
667 local blocksize=$(_get_block_size $SCRATCH_MNT)
668 local test_contents_files=()
669 local test_filenames_files=()
670 local i src dir dst inode blocklist \
671 padding_flag padding dir_inode len name f nonce decrypted_name
673 # Create files whose encrypted contents we'll verify. For each, save
674 # the information: (copy of original file, inode number of encrypted
675 # file, comma-separated block list) into test_contents_files[].
676 echo "Creating files for contents verification" >> $seqres.full
678 rm -f $tmp.testfile_*
679 for src in /dev/zero /dev/urandom; do
680 head -c $((4 * blocksize)) $src > $tmp.testfile_$i
683 dir=$SCRATCH_MNT/encdir
685 _set_encpolicy $dir $keyspec $set_encpolicy_args -f $policy_flags
686 for src in $tmp.testfile_*; do
689 inode=$(stat -c %i $dst)
690 blocklist=$(_get_ciphertext_block_list $dst)
691 test_contents_files+=("$src $inode $blocklist")
694 # Create files whose encrypted names we'll verify. For each, save the
695 # information: (original filename, inode number of encrypted file, inode
696 # of parent directory, padding amount) into test_filenames_files[]. Try
697 # each padding amount: 4, 8, 16, or 32 bytes. Also try various filename
698 # lengths, including boundary cases. Assume NAME_MAX == 255.
699 echo "Creating files for filenames verification" >> $seqres.full
700 for padding_flag in 0 1 2 3; do
701 padding=$((4 << padding_flag))
702 dir=$SCRATCH_MNT/encdir.pad$padding
704 dir_inode=$(stat -c %i $dir)
705 _set_encpolicy $dir $keyspec $set_encpolicy_args \
706 -f $((policy_flags | padding_flag))
707 for len in 1 3 15 16 17 32 100 254 255; do
708 name=$(tr -d -C a-zA-Z0-9 < /dev/urandom | head -c $len)
710 inode=$(stat -c %i $dir/$name)
711 test_filenames_files+=("$name $inode $dir_inode $padding")
715 # Now unmount the filesystem and verify the ciphertext we just wrote.
718 echo "Verifying encrypted file contents" >> $seqres.full
719 for f in "${test_contents_files[@]}"; do
720 read -r src inode blocklist <<< "$f"
721 nonce=$(_get_encryption_nonce $SCRATCH_DEV $inode)
722 _dump_ciphertext_blocks $SCRATCH_DEV $blocklist > $tmp.actual_contents
723 $crypt_contents_cmd $contents_encryption_mode $raw_key_hex \
724 --file-nonce=$nonce --block-size=$blocksize \
725 --inode-number=$inode < $src > $tmp.expected_contents
726 if ! cmp $tmp.expected_contents $tmp.actual_contents; then
727 _fail "Expected encrypted contents != actual encrypted contents. File: $f"
729 $crypt_contents_cmd $contents_encryption_mode $raw_key_hex \
730 --decrypt --file-nonce=$nonce --block-size=$blocksize \
731 --inode-number=$inode \
732 < $tmp.actual_contents > $tmp.decrypted_contents
733 if ! cmp $src $tmp.decrypted_contents; then
734 _fail "Contents decryption sanity check failed. File: $f"
738 echo "Verifying encrypted file names" >> $seqres.full
739 for f in "${test_filenames_files[@]}"; do
740 read -r name inode dir_inode padding <<< "$f"
741 nonce=$(_get_encryption_nonce $SCRATCH_DEV $dir_inode)
742 _get_ciphertext_filename $SCRATCH_DEV $inode $dir_inode \
745 $crypt_filename_cmd $filenames_encryption_mode \
746 $raw_key_hex --file-nonce=$nonce --padding=$padding \
747 --block-size=255 --inode-number=$dir_inode \
749 if ! cmp $tmp.expected_name $tmp.actual_name; then
750 _fail "Expected encrypted filename != actual encrypted filename. File: $f"
752 $crypt_filename_cmd $filenames_encryption_mode $raw_key_hex \
753 --decrypt --file-nonce=$nonce --padding=$padding \
754 --block-size=255 --inode-number=$dir_inode \
755 < $tmp.actual_name > $tmp.decrypted_name
756 decrypted_name=$(tr -d '\0' < $tmp.decrypted_name)
757 if [ "$name" != "$decrypted_name" ]; then
758 _fail "Filename decryption sanity check failed ($name != $decrypted_name). File: $f"
763 # fscrypt UAPI constants (see <linux/fscrypt.h>)
765 FSCRYPT_MODE_AES_256_XTS=1
766 FSCRYPT_MODE_AES_256_CTS=4
767 FSCRYPT_MODE_AES_128_CBC=5
768 FSCRYPT_MODE_AES_128_CTS=6
769 FSCRYPT_MODE_ADIANTUM=9
771 FSCRYPT_POLICY_FLAG_DIRECT_KEY=0x04
772 FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64=0x08
773 FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32=0x10
775 FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR=1
776 FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER=2
778 _fscrypt_mode_name_to_num()
783 AES-256-XTS) echo $FSCRYPT_MODE_AES_256_XTS ;;
784 AES-256-CTS-CBC) echo $FSCRYPT_MODE_AES_256_CTS ;;
785 AES-128-CBC-ESSIV) echo $FSCRYPT_MODE_AES_128_CBC ;;
786 AES-128-CTS-CBC) echo $FSCRYPT_MODE_AES_128_CTS ;;
787 Adiantum) echo $FSCRYPT_MODE_ADIANTUM ;;
788 *) _fail "Unknown fscrypt mode: $name" ;;
792 # Verify that file contents and names are encrypted correctly when an encryption
793 # policy of the specified type is used.
795 # The first two parameters are the contents and filenames encryption modes to
796 # test. The following optional parameters are also accepted to further modify
797 # the type of encryption policy that is tested:
799 # 'v2': test a v2 encryption policy
800 # 'direct': test the DIRECT_KEY policy flag
801 # 'iv_ino_lblk_64': test the IV_INO_LBLK_64 policy flag
802 # 'iv_ino_lblk_32': test the IV_INO_LBLK_32 policy flag
804 _verify_ciphertext_for_encryption_policy()
806 local contents_encryption_mode=$1
807 local filenames_encryption_mode=$2
809 local policy_version=1
811 local set_encpolicy_args=""
812 local crypt_util_args=""
813 local crypt_util_contents_args=""
814 local crypt_util_filename_args=""
823 if [ $contents_encryption_mode != \
824 $filenames_encryption_mode ]; then
825 _fail "For direct key mode, contents and filenames modes must match"
827 (( policy_flags |= FSCRYPT_POLICY_FLAG_DIRECT_KEY ))
830 (( policy_flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 ))
833 (( policy_flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 ))
836 _fail "Unknown option '$opt' passed to ${FUNCNAME[0]}"
840 local contents_mode_num=$(_fscrypt_mode_name_to_num $contents_encryption_mode)
841 local filenames_mode_num=$(_fscrypt_mode_name_to_num $filenames_encryption_mode)
843 set_encpolicy_args+=" -c $contents_mode_num"
844 set_encpolicy_args+=" -n $filenames_mode_num"
846 if (( policy_version > 1 )); then
847 set_encpolicy_args+=" -v 2"
848 crypt_util_args+=" --kdf=HKDF-SHA512"
849 if (( policy_flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY )); then
850 crypt_util_args+=" --mode-num=$contents_mode_num"
851 elif (( policy_flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 )); then
852 crypt_util_args+=" --iv-ino-lblk-64"
853 crypt_util_contents_args+=" --mode-num=$contents_mode_num"
854 crypt_util_filename_args+=" --mode-num=$filenames_mode_num"
855 elif (( policy_flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 )); then
856 crypt_util_args+=" --iv-ino-lblk-32"
857 crypt_util_contents_args+=" --mode-num=$contents_mode_num"
858 crypt_util_filename_args+=" --mode-num=$filenames_mode_num"
861 if (( policy_flags & ~FSCRYPT_POLICY_FLAG_DIRECT_KEY )); then
862 _fail "unsupported flags for v1 policy: $policy_flags"
864 if (( policy_flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY )); then
865 crypt_util_args+=" --kdf=none"
867 crypt_util_args+=" --kdf=AES-128-ECB"
870 set_encpolicy_args=${set_encpolicy_args# }
872 _require_scratch_encryption $set_encpolicy_args -f $policy_flags
873 _require_test_program "fscrypt-crypt-util"
874 _require_xfs_io_command "fiemap"
875 _require_get_encryption_nonce_support
876 _require_get_ciphertext_filename_support
877 if (( policy_version == 1 )); then
878 _require_command "$KEYCTL_PROG" keyctl
881 echo "Creating encryption-capable filesystem" >> $seqres.full
882 if (( policy_flags & (FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 |
883 FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) )); then
884 _scratch_mkfs_stable_inodes_encrypted &>> $seqres.full
886 _scratch_mkfs_encrypted &>> $seqres.full
890 crypt_util_args+=" --fs-uuid=$(blkid -s UUID -o value $SCRATCH_DEV | tr -d -)"
892 crypt_util_contents_args+="$crypt_util_args"
893 crypt_util_filename_args+="$crypt_util_args"
895 echo "Generating encryption key" >> $seqres.full
896 local raw_key=$(_generate_raw_encryption_key)
897 if (( policy_version > 1 )); then
898 local keyspec=$(_add_enckey $SCRATCH_MNT "$raw_key" \
901 local keyspec=$(_generate_key_descriptor)
903 _add_session_encryption_key $keyspec $raw_key
905 local raw_key_hex=$(echo "$raw_key" | tr -d '\\x')
908 echo -e "Verifying ciphertext with parameters:"
909 echo -e "\tcontents_encryption_mode: $contents_encryption_mode"
910 echo -e "\tfilenames_encryption_mode: $filenames_encryption_mode"
911 [ $# -ne 0 ] && echo -e "\toptions: $*"
913 _do_verify_ciphertext_for_encryption_policy \
914 "$contents_encryption_mode" \
915 "$filenames_encryption_mode" \
917 "$set_encpolicy_args" \
920 "$crypt_util_contents_args" \
921 "$crypt_util_filename_args"