Как и у любого пользователя Андроид у меня есть аккаунт в Гугле. А значит, кроме всего прочего, есть аж целых 15 гигабайт облачного хранилища, где можно что-то хранить, на случай всяких внезапных проблем с локальным оборудованием.
Традиционно, для этого используется либо приложение Google Drive, либо веб-интерфейс. Но ни то, ни другое не очень-то удобно на компьютере, особенно когда привык просто работать с произвольными файлами, которые куда-нибудь копируются.
И тем более - плохо подходит для автоматизации.
Второй возникающий вопрос - всё, что хранится не в вашем собственном облачном хранилище - в принципе доступно кому-нибудь не вам. И хорошо, если ваши личные документы читает какой-нибудь бот, для которого вы - всего лишь один из миллиардов анонимусов, хуже если информация утечет куда не надо и попадет кому не нужно.
Вот эти две проблемки попробуем решить.
Для работы с разными облачными системами есть неплохая программа rclone.
У нее много полезных возможностей, в чем-то она напоминает rsync, только умеет работать с разными облаками и протоколами обмена, но в данном случае это не обзор программы, а просто описание подхода в целом.
Итак, установим rclone:
apt install rclone
Общий принцип следующий: нужно зарегистрировать в программе удаленное хранилище, затем создать локальный каталог, и можно копировать туда‑сюда файлы, синхронизировать их с облаком, или просто загружать и удалять отдельные файлы.
Имеется подробный man, несложный синтаксис команд. Всё это из командной строки, то есть можно легко автоматизировать задачи создания бекапов.
В моем случае — на локальном сервере выделяю каталог, данные из которого будут периодически заливаться на Drive.
Но, учитывая возможность что Google в любой момент может стать недоступным, по разным там причинам, будет еще один сервер, в другом месте, который будет забирать с Drive залитые туда файлы.
Таким образом получаем три разных места хранения: локальный сервер, облако, и удаленный независимый сервер, не связанный с первым.
Настраиваем rclone:
rclone config
New remote
Назовем его как-то - test1
Укажем тип - drive
Client id - если уже есть, можно указать свой, если нет - оставляем пустое поле
Client secret - соответственно также
Scope - 1, full access
Service account file - пусто
Edit advansed config - No
Use auto config:
Тут возможны два варианта:
если rclone запускается на рабочей машине, с установленным браузером — можно ответить Yes — откроется окно браузера, нужно выбрать аккаунт и разрешить приложению доступ к Drive.
если rclone запускается на удаленной машине через SSH — нужно ответить No и получить ссылку, которую надо будет открыть с помощью rclone на рабочей машине, чтобы разрешить доступ, получить код, скопировать его и ввести в терминале на удаленной машине.
Configure as Shared Drive — No
Keep this remote — Yes
После настройки в файле ~/.config/rclone/rclone.conf появится запись о настроенном подключении.
В принципе, эту запись можно просто скопировать на другую машину, если надо настроить доступ и там тоже.
Теперь можно копировать файлы, примерно так:
mkdir my_google_drive
rclone copy test1:/ my_google_drive --drive-acknowledge-abuse --update
rclone copy my_google_drive test1:/ --drive-acknowledge-abuse --update
rclone sync my_google_drive test1:/ --drive-acknowledge-abuse --update
Подробно возможные команды расписаны в man rclone. Есть возможность даже примонтировать Drive как диск через FUSE.
То есть, теперь можно просто закидывать файлы в нужный каталог, откуда они будут сами по крону загружаться в облако, а потом где-то на удаленном сервере точно так же сами выгружаться оттуда.
Ну и конечно, будут доступны через Google Drive на мобильном телефоне.
Но это только часть дела. Теперь надо подумать и о безопасности данных.
Зашифровать файл в Линуксе очень просто, для этого можно использовать обычный openssl:
openssl enc -aes-256-ctr -salt -in input.file -out output.file -pbkdf2 -pass stdin
Получим зашифрованный файл output.file.
Расшифровка - с параметром -d:
openssl enc -aes-256-ctr -d -in input.file -out output.file -pbkdf2 -pass stdin
Если же указать -pass file:keyfile - в качестве пароля будет использовано содержимое файла keyfile, что удобно для автоматического шифрования большого количества файлов: если держать keyfile в секретном месте, а в облако выгружать исключительно зашифрованные файлы - расшифровать их будет не очень просто.
То есть, можно создать скрипт, который будет шифровать все файлы в каталоге, перемещать шифрованные в другой каталог, и потом загружать в облако, на хранение.
Для расшифровки понадобится вспомнить пароль, и использованный криптоалгоритм.
Сам по себе openssl при расшифровке не проверяет, правильно ли он расшифровал - если вы ввели неверный пароль, он что-то там "расшифрует", но насколько эти данные соответствуют оригиналу - он не знает.
Для автоматического шифрования этого достаточно: все файлы зашифрованы одинаково, если правильно расшифрован один - значит расшифруются все. Запаковывать периодические бекапы, например - подойдет.
Но для повседневного ручного использования это не очень удобно.
Во‑первых, нужно помнить синтаксис командной строки, во‑вторых — используемый тип шифрования. Отсутствует проверка «тот ли это файл вообще?», отсутствует контроль правильности расшифровки.
Но всё это можно добавить.
Итак, задача — сделать простой инструмент для командной строки, чтобы можно было зашифровать файл и расшифровать его обратно.
Для этого сделаем две команды, encrypt & decrypt, с поддержкой проверки формата зашифрованного файла и контролем корректности расшифровки.
Сначала — encrypt:
#!/bin/bash
MAGICK="enc1"
if [ -f "$1" ] ; then
echo -n "Enter password: "
read -s pass1
echo
if [ "x$pass1" = "x" ] ; then
exit 0
fi
output="$1.enc"
echo -n "$MAGICK" > "$output"
openssl dgst -sha256 -binary "$1" >> "$output"
echo -n "$pass1" | openssl enc -aes-256-ctr -salt -in "$1" -pbkdf2 -pass stdin >> "$output"
fi
Что он делает? Создается файл.enc, в заголовке которого записывается придуманное MAGIC word — просто 4 байта сигнатуры.
Затем рассчитывается sha256-хеш оригинального файла, и записывается следом в виде 32 байт.
Затем шифруется сам файл, и записывается после заголовка. Готово.
Конечно, можно усложнить, добавить параметр для поддержки ключевого файла или чего‑нибудь еще, но цель была как раз в создании простого и удобного инструмента для шифрования файла по паролю.
Если была бы задача, например, шифровать поток по ключу — проще написать другой, тоже простой в применении скрипт‑фильтр.
А вот с расшифровшиком decrypt сложнее, потому что добавлены проверки:
#!/bin/bash
MAGICK="enc1"
if [ -f "$1" ] ; then
# проверка сигнатуры
echo -n "$MAGICK" | cmp -n 4 -s - "$1"
if [ $? -ne 0 ]; then
echo "File $1 has unknown format"
exit 1
fi
# проверка "расширения"
orig=$(echo $1 | grep -oP '[^/]+(?=\.enc$)')
if [ "x$orig" = "x" ] ; then
echo "File $1 has unknown format"
exit 1
fi
# проверка наличия файла
if [ -f "$orig" ] ; then
msg="File $orig already exists, enter new name or overwrite? "
echo "$msg"
read -e -i "$orig" -p "> " orig
echo
fi
if [ "x$orig" = "x" ] ; then
# пользователь стер название
exit 0
fi
# ввод пароля
read -s -p "Enter password: " pass1
echo
if [ "x$pass1" = "x" ] ; then
exit 0
fi
# создаем временный файл и pipe в локальном каталоге
tmp_out=$(mktemp -p . )
tmp_in=$(mktemp -u -p .)
mkfifo "$tmp_in"
# забираем шифрованную часть файла
tail -c +37 "$1" > "$tmp_in" &
# расшифровка
echo -n "$pass1" | openssl enc -aes-256-ctr -d -in "$tmp_in" -out "$tmp_out" -pbkdf2 -pass stdin
rm "$tmp_in"
# проверка хеша
openssl dgst -sha256 -binary "$tmp_out" | cmp -n 32 -s --ignore-initial=0:4 - "$1"
if [ $? -ne 0 ]; then
echo "Incorrect password"
rm "$tmp_out"
exit 2
fi
mv "$tmp_out" "$orig"
exit 0
fi
Во-первых, проверяется наличие MAGIC word — читаем первые 4 байта файла.
Во‑вторых, проверяется «расширение» — оно должно быть.enc, и оно убирается, чтобы получить исходное имя файла. Если имя получилось пустым — считаем, что это неправильный файл.
В третьих, проверяем наличие расшифрованного файла — будем его перезаписывать или создаем новый?
И только потом — расшифровка.
При этом есть нюанс: для рашифровки нужно взять только часть входного файла после заголовка, начиная с 37 байта.
Это несложно сделать, перенаправив данные в stdout, тогда openssl должен получить их через stdin, но stdin уже занят вводом пароля, поэтому данные отправляются через FIFO‑pipe.
Получившийся после рашифровки временный файл проверяется по sha256, и если хеш совпадает с указанным в заголовке — можно считать, что файл расшифрован правильно.
Ну и наконец можно проверить:
encrypt somefile
decrypt somefile.enc
Теперь можно легко и быстро шифровать и расшифровывать файлы, без установки других, специализированных пакетов. Чисто для собственного использования.