Немного очевидного

Бэкапы надо хранить (лучше - хранить во множестве копий, в том числе, обязательно, где-то снаружи) и их надо шифровать. С этим вроде как все согласны, но на самом деле - мало кто делает. Значит, люди делятся на тех, кто еще не шифрует бэкапы (не смогли еще реалистично представить-ощутить возможные риски) и ответственных опытных людей, чьи дикпики увидел весь Интернет (кого мы знаем, образно выражаясь, в лицо). Теперь, когда мы уже, оказывается, некоторым образом давно знакомы, позвольте перейти к статье.

Крипто Дисклеймер

Автор не криптограф, и даже не претендует на это звание. А тема шифрования - сложная, и без понимания легко сделать так, что на первый взгляд будет казаться безопасным (например, достаточно хорошо зашифрованым), но фактически будет почти открытым.

Кто не в курсе, рекомендую потратить 2-3 минуты и немного ознакомиться с ECB-пингвином.

Я однажды так влетел (к счастью, ошибку нашел сам). Выбрал режим склейки блоков ECB (они там разные есть ECB, CBC, CTR, GCM, XTS) - я логично решил, что криптостойкость может быть разная, но совсем уж фигни в openssl не будет. И ошибся. Криптография и популярные стандартные крипто-инструменты позволяют выстрелить себе в ногу, позволяют обмануть себя ложным чувством безопасности.

Тем не менее, я не сразу нашел хороший гайд по той задаче, которая мне нужна (уверен, они есть, но мне не попались), поэтому, пусть будет еще один.

Что такое age и можно ли ему доверять?

age (произносится не "эйдж", а удобно, по-русски, "аге", с "г" как в "гиф") это новый, популярный инструмент шифрования (17k звезд звезд на github). age использует связку алгоритмов ChaCha20 для симметричного шифрования с алгоритмом имитовставки (Message authentication code, MAC, если по нашему) Poly1305 (RFC7539) от D. J. Bernstein. Того самого, который изобрел ed25519, который вы (будем надеяться) используете в ssh ключах. Кстати, этот ed25519 используется так же и в wireguard и в age тоже.

Установить можно просто через apt install age .

Автор - утилиты (можно ли ей доверять?) Filippo Valsorda работал в крипрографической команде Cloudflare, возглавляет Go security team в Google.

Просто используем!

Сначала - самое простое шифрование, просто паролем, для самых маленьких.

# encrypt
$ age -p -o paris.jpg.age paris.jpg 
Enter passphrase (leave empty to autogenerate a secure one): 
Confirm passphrase: 

# decrypt
$ age -d -o paris-decrypted.jpg paris.jpg.age 
Enter passphrase:

Этого уже достаточно, чтобы хранить файлы где-нибудь на яндекс.диске и не бояться, что Яндекс, взломщик или спецслужбы будут их читать.

Но давайте рассмотрим более интересный вариант, который уже не стыдно использовать в продакшне. Мы хотим шифровать бэкапы баз данных перед тем, как загружать их на S3. Тут возникает несколько сложностей:

  • Мы не хотим хранить какие-то приватные или симметричные ключи на сервере.

  • Несколько человек в компании ("получатели") должны иметь возможность расшифровать бэкапы. Чтобы даже если один ушел из команды, кто-то другой может расшифровать бэкап.

  • Мы не хотим использовать какой-то один "супер-ключ" и давать его всем. Как правило, такой ключ быстро утекает (через взломанные мессенджеры, переписки) и что самое плохое - мы даже не можем узнать, от кого он утек. Каждый получатель должен иметь возможность расшифровать своим индивидуальным ключом, который он нигде не светит.

Сначала, чуть-чуть теории, как это работает. Асимметричное шифрование не пригодно для шифрования больших объемов данных. Поэтому генерируется случайный ключ для шифрования, сам файл симметрично шифруется алгоритмом ChaCha20 с использованием этого ключа, а дальше в выходной файл несколько раз добавляется этот ключ, зашифрованный публичным ключом каждого из получателей.

Откуда взять ключи? Первый вариант - сгенерировать их: age-keygen -o key.txt создаст пару публичных и приватных ed25519 ключей. Но... а зачем? В наше время у всех есть SSH ключ в формате ed25519 ну или на худой конец RSA. Не будем плодить ключи, будем использовать ключи SSH, которые у нас уже есть, age это умеет! Получателей к шифрованному файлу можно добавлять повторяя аргумент -r KEY (значение публичного ключа прямо аргументом передаем), или -R file - где в файле перечислены (один или несколько) публичные ключи. Ваш ~/.ssh/id_ed25519.pub вполне подходит в качестве ключа для шифрования. Но мы всех получателей запишем в один файл recipients.txt:

# john doe
ssh-ed25519 AAAA....

# my key
ssh-ed25519 AAAA....

Да, пустые строки и решетки - можно. и даже ~/.ssh/authorized_keys вполне подходит в качестве такого файла.

Ну и поехали:

$ age -o paris.jpg.age -R recipients.txt paris.jpg

Полученный paris.jpg.age файл можно свободно заливать в ваш любимый файлообменник, хоть в S3, хоть в дропбокс хоть в skype.

Если же мы вдруг решили восстановиться и хотим расшифровать:

$ age -d -o paris.jpg -i ~/.ssh/id_ed25519 paris.jpg.age

Как видите, все просто, а главное - тут нет лишних непонятных кнопочек и крутилочек, которые можно было бы неправильно нажать.

Почему мне нравится age (холиварное немного)

ChatGPT удалось очень удачно выразить всю простоту и ясность понимания криптоалгоритмов и их связей в голове обычного пользователя. Примерно такой вот схемой руководствуются пользователи, когда пишут параметры командной строки для openssl
ChatGPT удалось очень удачно выразить всю простоту и ясность понимания криптоалгоритмов и их связей в голове обычного пользователя. Примерно такой вот схемой руководствуются пользователи, когда пишут параметры командной строки для openssl

Во-первых - age, это просто и дешево и быстро в реализации. Как говорил Борис Бритва про криптографию: простота это хорошо, простота - это надежно! С практической точки зрения, age, это такой инструмент, про который вы сейчас прочитали статью, через 15 минут поигрались и увидели, что он работает и к вечеру начали качественно и надежно шифровать бэкапы. Это - работает. Какие-то сложные схемы - там уже бОльшая вероятность, что пока вы с ними разберетесь на достаточном уровне, там возникнут другие важные дела, задачи, вы переключитесь и просто не сделаете никакое шифрование. Поэтому - я сторонник простых и надежных решений.

Второе, у простоты age есть и преимущества с криптографической стороны. Скорее всего выбранные автором алгоритмы достаточно хороши для этой (вполне типичной для всех) задачи, в которой не требуется подбирать себе особенные алгоритмы "по своей уникальной ноге". Я думаю, компетентный автор утилиты сделал выбор алгоритмов лучше, чем сделал бы я (с моей криптограмотностью, как на иллюстрации выше).

Третий плюс - у age просто нет ненужных крутилочек, опций, которые вам были бы не нужны. Нет риска, что воспользовавшись age неправильно вы выстрелите себе в ногу и получите бэкапы, которые кто-то взломает на домашнем компе за час.

Я не пользовался активно PGP/GPG, кроме как поиграться, но пользовался openssl. Опыт был настолько болезненный и травмирующий, что моя психотравма от использования openssl для работы с X.509 сертификатами сублимировалась в проект showcert (статья на хабре про showcert), 70+ звезд на гитхабе. Все типовые операции с сертификатами, от просмотра сертификата из файла или на удаленном сервере и до создания своего CA делаются простыми, короткими интуитивными командами. Сравните:

# you will never forget how to read certificate with showcert
showcert habr.com 

# two redirections, pipe, two invocations and 5 unneeded options
openssl s_client -connect habr.com:443 /dev/null | openssl x509 -inform pem -text

Я много лет использовал openssl для проверки сертификатов и никогда не мог напечатать этот конвейер из двух команд по памяти без ошибок - всегда начинал с гугла, чтобы найти ее. Сравните с первой командой, где невозможно ошибиться, просто негде. Поэтому для меня age выглядит таким же разумным упрощением.

openssl у меня оставил впечатление не инструмента для решения задачи, а скорее прокладки, CLI-интерфейса к очень богатому зоопарку различных криптографических функций (из которых 99% вам не нужно, а оставшимся 1% вы не понимаете как пользоваться, когда GCM лучше, чем XTS, но можете загуглить и скопировать заклинание из браузера в шелл).

Ниже, в "ссылках для холивара" есть хорошая иллюстрация (stackoverflow), когда длинное "заклинание" с openssl в самом деле шифрует файл. Этот ответ заплюсован, многие тысячи людей копируют и используют его, и только ниже в комментариях к ответу, написано, почему так делать неправильно. Тот самый эффект ECB-пингвина из начала статьи. Люди делают криптографию на основе полуграмотного комментария неизвестно кого, заплюсованного еще более неграмотными в криптографии людьми.

А вот age - это именно утилита для шифрования, инструмент для конкретного предназначения. Не претендует на то, чтоб быть швейцарским ножом, которым можно и звездолет починить, но отлично нарезает сервелат.

Еще, мне очень понравился аргумент из статьи @stargrave2на хабре Libre/OpenPGP vs OpenSSH/age :

Когда мы в последний раз видели чтобы ломали какой-то формат или протокол, потому что в нём был уязвимый шифр? RC4, который нигде и не использовался серьёзно, если были привлечены криптографы? А вот если в протоколе или формате можно согласовывать/выбирать эти алгоритмы, то downgrade атак или уязвимостей в ASN.1 парсерах (из-за вынужденно сложных форматов) мы видели тьму. Решения с моно-алгоритмами просто не подвержены этим атакам.

Почитать по теме и для холиваров age/pgp/openssl

Странички на stackoverflow стоит читать с комментариями

Комментарии (15)


  1. ky0
    05.11.2024 12:57

    Мы не хотим использовать какой-то один "супер-ключ" и давать его всем.

    И вместо этого мы сделаем несколько "супер-ключей"!


    1. xenon Автор
      05.11.2024 12:57

      Каждым из них можно расшифровать, да. Но за счет того, что их несколько - каждый хранится у отдельного человека в его темном чулане и не пересылается нигде, не оказывается в руках ни у кого. Это понижает шанс утечки.

      Просто неприятный опыт с "суперключом" (единым) я наблюдал. Там правда был не ключ от шифрования, а тестовые логин/пароль к одной системе. Ими пользовались N человек, пересылали друг-другу, потом какие-то люди уходили из команды (а пароль оставался тем же), а потом он утек. И утек, как мы предполагаем - из переписки. А вот чью переписку (или мессенджер) взломали - мы так и не смогли узнать. Нет переписки, передачи, копирования ключа - нет сопряженных с этим рисков.


      1. ky0
        05.11.2024 12:57

        Если уж двигаться по этому пути, то немного подальше - чтобы в одиночку никто расшифровать не мог.

        Знание "у кого утёк ключ" особой практической ценности не несёт - данные всё равно скомпрометированы.


        1. Tsimur_S
          05.11.2024 12:57

          Если пароль один на всех то кроме утечки из ./ssh, где он кстати лежит под паролем, добавляется еще возможность утечки из переписки, шарить же его как то нужно.

          Можно конечно представить совсем отмороженных которые будут шарить свои приватные ключи но это техническими средствами не исправляется. Точно так же как и в вашей ситуации можно представить что все просто поделятся ключами друг с другом и получат "ключ всевластья".


        1. xenon Автор
          05.11.2024 12:57

          У нас немного другие риски. Да, не хотелось бы, чтобы архивы утекли. Это было бы плохо, но не катастрофа. А вот катастрофой была бы другая опасность - если нам нужен бэкап, а мы не можем его получить (или скачали, но не можем расшифровать). Например, потому что нужен ключ человека, который уволился, умер, просто потерял/поменял себе ключ. Все-таки бэкапы делаются чтобы иногда ими пользоваться. Поэтому усиливать конфиденциальность имеет смысл только до той поры, пока это не начинает конфликтовать с доступностью бэкапов для нас самих.

          А про знание, откуда утек ключ - мне оно кажется очень важным. Ключи ведь не должны утекать. Значит, где-то что-то у нас неправильно. Поменяем мы ключ и новый тем же образом утечет. Надо знать, где проблема, чтобы она не повторилась снова.


  1. karrakoliko
    05.11.2024 12:57

    зачем тащить какую то утилиту для синхронного шифрования, если gpg -c secret.tar.gz?


    1. xenon Автор
      05.11.2024 12:57

      Вы имеете в виду "симметричного", вероятно?
      В случае с age будет связка: ChaCha20-Poly1305 для шифрования и PBKDF2 для наследования ключа из пароля.
      В случае с gpg будет (по умолчанию) связка: AES-256 для шифрования и SHA-1 с солью для создания ключа из пароля.

      И ChaCha20 более современный и считается более стойким, чем AES-256, и SHA-1 считается устаревшим для криптографических целей. Перебор паролей с SHA-1 будет гораздо быстрее, чем с PBKDF2 (специально замедленный алгоритм).

      Но в целом, хоть алгоритмы в age более надежные, gpg "для дома для семьи" тоже вполне подойдет (мы же не рассматриваем вариант, что ЦРУ будет ваши файлы взламывать). Более опасная разница в том, что если начать настраивать алгоритмы ручкам в gpg, то там можно сильно напортачить (age более предсказуем в этом плане, он вот всегда с одной конфигурацией работает).

      А так - если удобно - то почему бы и не тащить gpg если он привычнее? Если у вас УЖЕ есть работающая схема шифрования на gpg, она проверена и все хорошо - я бы ради преимущества в алгоритмах менять бы ее не стал (по крайней мере в обозримом будущем).


    1. ThingCrimson
      05.11.2024 12:57

      Основная прелесть здесь не в симметричном шифровании, а с использованием ключевых пар (как своих, так и уже имеющихся от OpenSSH). Да, gpg много где есть (но не везде ставится по умолчанию); но какой же он огромный и переусложнённый (один Web Of Trust, от PGP тянущийся, чего стоит).

      Кстати, git тоже позволяет подписывать коммиты при помощи ключевых пар от OpenSSH, тенденция!


      1. xenon Автор
        05.11.2024 12:57

        Мне кажется, тенденция в том, что во многих вопросах мир давно перешел порог разумного усложнения и по инерции прошел существенно дальше. И теперь я много где вижу откат к простоте (даже пусть и не бесплатно, с потерей каких-то плюшечек, которые не очень-то и жалко).

        К примеру, сделали когда-то в *nix'ах shared библиотеки, не такой уж простой механизм, чтобы один код использовать в разных программах - хорошая идея вроде бы! Экономит место на диске, экономит оперативку. Для него пришлось использовать apt в debian/ubuntu для контроля зависимостей. При этом зависимости конфликтуют, потребовались виртуалки-контейнеры для изоляции. А тут появляется golang с простой идеей, что у них никаких shared библиотек не будет, как в gcc --static, все всегда будет собираться в один файл. Тупо как во времена MS DOS. Да, файл жирный будет, да и фиг с ним. И... оказалось, что всех устраивает! На самом деле исходно и gcc так мог легко, но не пользовались этим, и фактически это оказалось одним из преимуществ golang.

        Во многих проектах виден жизненный цикл - появляется фанатский опен-сорсный проект, написанный за месяц на коленке, простой, эффективный, и он взлетает, становится популярным. Какое-то время он оправданно развивается - фиксятся баги, дописываются нужные многим функции. А потом дописывают туда одну фичу, другую, пятую, десятую, появляются корпоративные клиенты которые платят чтоб им сделали нужные им функции вроде масштабирования, резервирования. И удобный велосипед превращается в тяжеленный аэробус. А тебе-то нужно в булочную через два дома ездить. И появляются новые проекты, которые "вот то же как в том, только lite версия, только простые самые важные фукции", снова возврат к велосипеду.


  1. NAI
    05.11.2024 12:57

    Как то оно не выглядит пригодным для бэкапов, по крайней мере для инкрементных.

    Для бэкапов, фанатам Filippo Valsora, лучше сразу смотреть restic, и читать его restic cryptography, в котором он пишет :"I'm going to use restic..."


    1. xenon Автор
      05.11.2024 12:57

      Хех, у нас как раз такая комбинация и используется :-). restic'ом файловые каталоги (огромные, но мало новых файлов) бэкапируется, а age - бэкапы баз данных.

      Для баз данных есть какой-то удобный способ инкрементальных бэкапов? (кроме бинлогов даже ничего и не приходит на ум). И вообще, когда проект брали - там была туева хуча баз данных непонятного предназначения и даже вот интересно было - есть ли способ узнать, за последний месяц что-то писалось в базу или нет, я не нашел инструментов для этого.

      С рестиком, правда (хоть и немного оффтопик) был однажды странный глюк, из-за которого я начал чуть побаиваться его. Решили мы еще один каталог кидать в restic ежедневно, кидали. А потом просто перестали его использовать, удалили. Но по крону - кидали (несуществующий каталог). И в какой-то момент его репозиторий этого несуществующего каталога внезапно неимоверно раздулся так, что у меня мониторинг заистерил. Возможно, они его не тестили, когда сто раз делается снапшот несуществующего каталога :-)


  1. g_sa
    05.11.2024 12:57

    А под Windows как работает?


    1. xenon Автор
      05.11.2024 12:57

      Не пробовал, но это же программа на Go - полагаю, что так же, из командной строки, без GUI.


    1. alextradex
      05.11.2024 12:57

      пример с паролем из статьи сработал только на шифрование, на расшифровку сыпал непобедимыми ошибками про ключ -o
      В документации нашел более лаконичные и работающие под windows примеры:

      #encrypt
      age -p secrets.txt > secrets.txt.age Enter passphrase (leave empty to autogenerate a secure one):
      #decrypt
      age -d secrets.txt.age > secrets.txt


  1. ThingCrimson
    05.11.2024 12:57

    Большое спасибо за статью! Как-то эта утилита до сих пор мимо меня проходила; уже поставил на линуксах (sudo apt install age) и на макосях (brew install age). Проверил с ключевыми парами от OpenSSH (RSA и ed25519) — работает как надо.

    Буду теперь использовать вместе (или вместо) GnuPG — он делает то же, и хорошо делает; но больно уж универсальным комбайном стремится стать. И если на системе его ещё нет, то теперь можно и не ставить, заменив на age.