Сравнение производительности различных систем шифрования под linux

в 11:08, , рубрики: linux, системное администрирование, шифрование, метки: , ,

В данной статье я попытаюсь сравнить производительность различных систем шифрования под linux. В теории, конечно, известно, какая система производительнее, и попытки посчитать производительность разных систем были (например). Truecrypt даже содержит встроенный бенчмарк (который показывает, однако, производительность на RAM, его можно использовать разве что для оценки скорости разных алгоритмов шифрования). Я же сделаю несколько другое — измерю скорость файловой системы, зашифрованной разными средствами, в процентном соотношении по сравнению с обычной нешифрованной файловой системой.
image

Шифровать будем отдельный раздел на отдельном HDD, не содержащий корневую файловую систему, алгоритмом, использующимся по-умолчанию в каждом конкретном случае. Как обычный пользователь, я не разбираюсь в нюансах стандартов шифрования (например, чем отличается хэширование RIPEMD-160 от Whirpool, какой из этих режимов быстрее, какой способствует более высокой защите), поэтому просто положимся на то, что производители каждого программного продукта выбрали достаточно криптостойкие параметры по-умолчанию. Может, это и не совсем корректно, т. к. производительность различных алгоритмов шифрования неодинакова. При желании, конечно можно сменить тип шифрования, но я не уверен, что во всех тестируемых продуктах существует абсолютно идентичный набор алгоритмов. Тестировать будем:

1) LUKS — нативная система шифрования, в теории должна быть самой быстрой. Тома, зашифрованные LUKS можно использовать в Windows через FreeOTFE.

2) Truecrypt — в отличии от LUKS имеет, кроме консольного, и GUI-интерфейс, что делает его на порядок удобнее в использовании. Мультиплатформенное ПО. Обеспечение двух уровней правдоподобного отрицания наличия зашифрованных данных, необходимого в случае вынужденного открытия пароля пользователем. Тома Truecrypt не имеют заголовка, их нельзя отличить от набора случайных данных. В теории медленнее, чем LUKS, т.к. использует FUSE.

3) eCryptfs — система, по умолчанию предлагаемая пользователям Ubuntu для шифрования домашних каталогов, поэтому и включена в данный тест. Работает поверх уже существующей ФС. Шифрует каждый файл отдельно, поэтому всем видны права, даты изменения, количество зашифрованных файлов; по-умолчанию также видны имена файлов, хотя и существует опция для их шифрования. Самое малофункциональное средство из представленных.

Итак, для тестов выделена отдельная машина довольно преклонного возраста в следующей конфигурации: ЦП — Intel Celeron 2000Mhz, ОЗУ — 512 Mb DDR PC2700, системный HDD — WD Caviar SE 5400 RPM 80Gb, тестовый HDD — WD Caviar SE 7200 RPM 80Gb.
ОС — Ubuntu 12.04 LTS, версии всего ПО актуальные для репозиториев этой ОС на момент написания статьи (Truecrypt 7.1a-linux-x86 не из репозиториев).

Тестировать будем дефолтную для большинства дистрибутивов файловую систему ext4. Для тестирования производительности будем использовать утилиту iozone3 и написанный «на коленке» shell-скрипт для измерения процентной разницы в тестах.

Скрипт для подсчёта. Особое внимание чистоте кода не уделялось, единственным критерием при написании было наличие правильного результата.

#!/bin/sh

gendifffile () {
#процедура генерирует файл, который удобно анализировать. Во-первых, обрезаются
#не подлежащие анализу строки; во-вторых, в каждой строке обрезаются первых два числа, обозначающие 
#размер файла и размер записи соответственно; в-третьих, весь файл выводится построчно - 
#один результат теста на одну строку
cat $1 | while read LINE ; do
	echo $LINE| grep "^[[:space:]]*[[:digit:]]" | awk '{for (i=3;i<=NF;i++) {print $i}}'
done >> $2
}

getline () {
#процедура выводит строку номер $2 файла $1
	head -n $2 "$1" | tail -n 1	
}

compare () {
#процедура сравнивает построчно файлы $1 и $2, вычисляя процентную разницу каждой пары тестов
#затем вычисляется среднее арифметическое значение, на сколько процентов быстрее или медленнее
#файл, содержащий первую группу тестов, файла, содержащего вторую группу
	P=0
	MAX=0
	L1=`cat "$1" | wc -l` #количество тестов в файле
	L2=`cat "$2" | wc -l`
	if [ $L1 -ne $L2 ]; then #если файлы содержат разное количество тестов, то сравнивать их мы не будем
		echo error
		return
	fi
	STEP=$(( $L1*5/100 ))
	J=0
	for I in `seq 1 $L1`; do
		J=$(( $J+1 ))
		if [ $J -eq $STEP ]; then
			J=0
			echo "$(( 100*$I/$L1 ))% завершено ($I из $L1)"
		fi
		A=`getline "$1" $I`
		B=`getline "$2" $I`
		if [ `echo $A > $B|bc -l` -eq 1 ]; then
			D=`echo "100-($B*100/$A)"|bc -l`
			if [ `echo $D > $MAX| bc -l` -eq "1" ]; then
				MAX=$D
				sleep 5
			fi
		else
			D=`echo "100-($A*100/$B)"|bc -l`
			if [ `echo $D > $MAX| bc -l` -eq "1" ]; then
				MAX=$D
				sleep 5
			fi
			D="-$D" #если значение имеет знак "-", значит, данный тест был выполнен быстрее 
				#во втором файле, а не в первом
		fi
		P=`echo "$P+$D"| bc -l`
	done	
	P=`echo $P/$L1| bc -l` #вычислим среднее арифметическое
	echo PERCENT=$P MAX_PERCENT=$MAX
}

genaverage () {
#процедура генерации подготовленного к анализу файла, каждой строкой которого является
#среднее арифметическое соответствующих строк всех файлов отчётов, лежащих в анализируемой директории
	AVG=`mktemp`	
	F=`ls "$1"|wc -l`	#количество файлов с отчётами в заданной директории
				#при условии, что там хранятся только такие файлы и больше ничего другого 
				#проверять корректность данного допущения мы не будем
	if [ ! -d "$1" -o $F -lt 2 ]; then 
		echo error >/dev/stderr #в этой процедуре будем выводить все сообщения в stderr, т.к.
					#stdout подставляется в другую процедуру
		rm -f $AVG
		exit
	fi
	TMP=`mktemp`
	find "$1" -type f| while read FILE; do	#для каждого файла отчёта iozone, лежащего в заданной директории
		I=`mktemp`			#сгенерируем временный файл, подготовленный для анализа
		gendifffile "$FILE" "$I"	#имена всех таких файлов запишем в "TMP" построчно
		echo "$I">>$TMP			
	done	
	L=`cat `getline "$TMP" 1`|wc -l`
	cat "$TMP"| while read LINE; do	#немного проверок не помешает
		L1=`cat "$LINE"| wc -l`	#все ли файлы содержат одинаковое количество тестов
		if [ $L -ne $L1 ]; then
			echo error >/dev/stderr
			exit
		fi
	done	
	STEP=$(( $L*5/100 ))
	J=0
	for I in `seq 1 $L`; do
		J=$(( $J+1 ))
		if [ $J -eq $STEP ]; then
			J=0
			echo "$(( 100*$I/$L ))% завершено ($I из $L)" >/dev/stderr
		fi
		SUMFILE=`mktemp` #таким образом я получаю значение переменной SUM из вложенного цикла
		SUM=0
		cat "$TMP"| while read LINE; do
			SUM=$((	`getline "$LINE" $I`+$SUM )) 
			echo $SUM > "$SUMFILE"
		done
		echo `tail -n 1 "$SUMFILE"`/$F|bc -l >> $AVG 	#получаем среднее арифметическое
								#и запишем его в соответствующее место
								#файла AVG
		rm -f "$SUMFILE"
	done
	cat "$TMP"| while read LINE; do #удалим временныe файлы
		rm -f "$LINE"
	done
	rm -f "$TMP"
	echo $AVG
}

printf %b "33[1;31mШаг 1/3n"
printf %b "33[1;37m"
echo Генерируем усреднённый файл для директории ""$1""
A=`genaverage "$1"`	
printf %b "33[1;31mШаг 2/3n"
printf %b "33[1;37m"
echo Генерируем усреднённый файл для директории ""$2""
B=`genaverage "$2"`
printf %b "33[1;31mШаг 3/3n"
printf %b "33[1;37m"
echo Сравниваем усреднённые файлы 
compare "$A" "$B"
rm -f $A $B		

Положимся на режим -a, в котором iozone должен произвести в автоматическом режиме серию тестов, которые покрывают всевозможные операции с файлами разных размеров и разной длиной записи (моя версия произвела 1638 тестов).
В ходе эксперимента выяснилось, что одна серия тестов iozone может отличаться от другой по производительности на 5%, поэтому я не буду рассчитывать на результаты одного-единственного набора тестов и поступлю таким образом: проведу набор тестов несколько раз и сгенерирую файл с усредненными значениями по каждому из тестов (во всех расчётах данной статьи под усредненными значениями понимается среднеарифметическое значение). После этого я сравню усредненный файл, содержащий серию тестов по незашифрованной файловой системе с аналогичным файлом, содержащим серию тестов на зашифрованной ФС таким образом: каждый тест первого файла будет сравнен с соответствующим тестом второго в процентном соотношении, результаты сложим, а сумму разделим на количество тестов, получив среднеарифметическое значение, на сколько процентов первая группа тестов быстрее или медленнее второй.
Также, для простой оценки скорости, в дополнение к вышеописанным вычислениям, проведем простенький тест — копирование средствами dd 500 мегабайт из urandom на зашифрованную ФС блоками, равными размеру кластера ext4 по-умолчанию (4 килобайта). dd if=/dev/urandom of=testfile bs=4k count=128000. Шифровать будет раздел целиком (за исключением eCryptfs, которая этого делать не умеет). Я не буду приводить команды для каждого конкретного случая, покажу только результаты.
Итак, приступим:

1) Система шифрования: нет
Количество проведенных серий тестов: 14
Средняя разница в производительности между одинаковыми сериями тестов: 1,3%
Результат dd: 524288000 bytes (524 MB) copied, 187.823 s, 2.8 MB/s

2) Система шифрования: LUKS. Используя ключи по-умолчанию, наш том будет зашифрован так:
Cipher name: aes
Cipher mode: cbc-essiv:sha256
Hash spec: sha1
Количество проведенных серий тестов: 8
Средняя разница в производительности между одинаковыми сериями тестов: 1,4%
Результат dd: 524288000 bytes (524 MB) copied, 199.505 s, 2.6 MB/s
Падение производительности по сравнению с нешифрованной ФС: 7,9%

3) Система шифрования: Truecrypt. Применяя все параметры по-умолчанию, том будет зашифрован AES с алгоритмом хеширования RIPEMD-160.
Количество проведенных серий тестов: 22
Средняя разница в производительности между одинаковыми сериями тестов: 3,2%
Результат dd: 524288000 bytes (524 MB) copied, 199.719 s, 2.6 MB/s
Падение производительности по сравнению с нешифрованной ФС: 7%

4) Система шифрования: eCryptfs
aes: blocksize = 16; keysize = 16
Количество проведенных серий тестов: 9
Средняя разница в производительности между одинаковыми сериями тестов: 0,9%
Результат dd: 524288000 bytes (524 MB) copied, 199.624 s, 2.6 MB/s
Падение производительности по сравнению с нешифрованной ФС: 49,5%

Итог: производительность eCryptfs по всевозможным файловым операциям оставляет желать лучшего, хотя обычный тест dd с оптимальным размером блока показывает скорость, аналогичную остальным системам шифрования. Шифровать целиком ей домашнюю директорию я бы не стал. Удобно применять лишь при шифровании отдельных поддиректорий. Ожидания меньшей производительности Truecrypt из-за использования FUSE не оправдались, в моём случае он оказался даже немного быстрее LUKS.

В дополнение, как бонус, приведу аналогичный тест dd для Truecrypt и LUKS, но для file-hosted контейнера (все параметры шифрования аналогичны).
1) LUKS
524288000 bytes (524 MB) copied, 207.07 s, 2.5 MB/s
2) Truecrypt
524288000 bytes (524 MB) copied, 205.046 s, 2.6 MB/s
Падение производительности можно объяснить тем, что появляются дополнительные накладные расходы на чтение файла контейтера с уже существующей файловой системы вместо прямого обращения к разделу.

Автор: infd

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js