#! /bin/bash # SPDX-License-Identifier: GPL-2.0 # Copyright 2020 Google LLC # # FS QA Test No. 613 # # Test that encryption nonces are unique and random, where randomness is # approximated as "incompressible by the xz program". # # An encryption nonce is the 16-byte value that the filesystem generates for # each encrypted file. These nonces must be unique in order to cause different # files to be encrypted differently, which is an important security property. # In practice, they need to be random to achieve that; and it's easy enough to # test for both uniqueness and randomness, so we test for both. # seq=`basename $0` seqres=$RESULT_DIR/$seq echo "QA output created by $seq" here=`pwd` tmp=/tmp/$$ status=1 # failure is the default! trap "_cleanup; exit \$status" 0 1 2 3 15 _cleanup() { cd / rm -f $tmp.* } # get standard environment, filters and checks . ./common/rc . ./common/filter . ./common/encrypt # remove previous $seqres.full before test rm -f $seqres.full # real QA test starts here _supported_fs generic _require_scratch_encryption -v 2 _require_get_encryption_nonce_support _require_command "$XZ_PROG" xz _scratch_mkfs_encrypted &>> $seqres.full _scratch_mount echo -e "\n# Adding encryption keys" _add_enckey $SCRATCH_MNT "$TEST_RAW_KEY" _add_enckey $SCRATCH_MNT "$TEST_RAW_KEY" -d $TEST_KEY_DESCRIPTOR # Create a bunch of encrypted files and directories -- enough for the uniqueness # and randomness tests to be meaningful, but not so many that this test takes a # long time. Test using both v1 and v2 encryption policies, and for each of # those test the case of an encryption policy that is assigned to an empty # directory as well as the case of a file created in an encrypted directory. echo -e "\n# Creating encrypted files and directories" inodes=() for i in {1..50}; do dir=$SCRATCH_MNT/v1_policy_dir_$i mkdir $dir inodes+=("$(stat -c %i $dir)") _set_encpolicy $dir $TEST_KEY_DESCRIPTOR dir=$SCRATCH_MNT/v2_policy_dir_$i mkdir $dir inodes+=("$(stat -c %i $dir)") _set_encpolicy $dir $TEST_KEY_IDENTIFIER done for i in {1..50}; do file=$SCRATCH_MNT/v1_policy_dir_1/$i touch $file inodes+=("$(stat -c %i $file)") file=$SCRATCH_MNT/v2_policy_dir_1/$i touch $file inodes+=("$(stat -c %i $file)") done _scratch_unmount # Build files that contain all the nonces. nonces_hex contains them in hex, one # per line. nonces_bin contains them in binary, all concatenated. echo -e "\n# Getting encryption nonces from inodes" echo -n > $tmp.nonces_hex echo -n > $tmp.nonces_bin for inode in "${inodes[@]}"; do nonce=$(_get_encryption_nonce $SCRATCH_DEV $inode) if (( ${#nonce} != 32 )) || [ -n "$(echo "$nonce" | tr -d 0-9a-fA-F)" ] then _fail "Expected nonce to be 16 bytes (32 hex characters), but got \"$nonce\"" fi echo $nonce >> $tmp.nonces_hex echo -ne "$(echo $nonce | sed 's/[0-9a-fA-F]\{2\}/\\x\0/g')" \ >> $tmp.nonces_bin done # Verify the uniqueness and randomness of the nonces. In theory randomness # implies uniqueness here, but it's easy enough to explicitly test for both. echo -e "\n# Verifying uniqueness of nonces" echo "Listing non-unique nonces:" sort < $tmp.nonces_hex | uniq -d echo -e "\n# Verifying randomness of nonces" uncompressed_size=$(stat -c %s $tmp.nonces_bin) echo "Uncompressed size is $uncompressed_size bytes" compressed_size=$($XZ_PROG -c < $tmp.nonces_bin | wc -c) echo "Compressed size is $compressed_size bytes" >> $seqres.full # The xz format has 60 bytes of overhead. Go a bit lower to avoid flakiness. if (( compressed_size >= uncompressed_size + 55 )); then echo "Nonces are incompressible, as expected" else _fail "Nonces are compressible (non-random); compressed $uncompressed_size => $compressed_size bytes!" fi # success, all done status=0 exit