| #! /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 |