Files
apfstests/tests/generic/613
T
Eric Biggers b09ba3318e generic: test that encryption nonces are unique and random
Test that encryption nonces are unique and random, where randomness is
approximated as "incompressible by the xz program".

This gets indirectly tested by generic/399, but there are some gaps.
It's good to test for this directly too.

This test runs and passes on ext4 and f2fs.  It doesn't currently run on
ubifs because _get_encryption_nonce() isn't implemented for ubifs yet.
(At some point I'll probably switch _get_encryption_nonce() to use
FS_IOC_GET_ENCRYPTION_NONCE, which was added in Linux 5.7.  But for now
I'd like to keep the tests using it runnable on older kernels too.)

Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
2020-11-02 00:25:08 +08:00

119 lines
3.7 KiB
Bash
Executable File

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