Перейти к содержимому
ecdsa.com

age или GPG: шифрование файлов и секретов в 2026 году

age делает одно: шифрует файлы для коротких открытых ключей или парольной фразой. GnuPG реализует весь OpenPGP, включая подписи, управление ключами и электронную почту, со всей сопутствующей сложностью.
Что сравниваетсяage (шифрование файлов)OpenPGP

age или GPG — это выбор между маленьким инструментом шифрования с единственным назначением и полной реализацией OpenPGP. age (формат age-encryption.org/v1, спецификация опубликована в C2SP) шифрует файл для одного или нескольких получателей. Каждый получатель — короткая строка вида age1…, открытый ключ SSH или постквантовый ключ age1pq1…; для инкапсуляции ключа используется X25519 или гибридный ML-KEM, а для полезной нагрузки — ChaCha20-Poly1305. GnuPG реализует OpenPGP: шифрование, подписи, сертификацию ключей, связки ключей, серверы ключей, смарт-карты и интеграцию с электронной почтой, и за ним стоят десятилетия совместимости.

Коротко

ageGnuPG (OpenPGP)
НазначениеТолько шифрование файловШифрование, подпись, сертификация, управление ключами
Спецификацияage v1 (C2SP): один формат, никаких версий для согласованияRFC 9580 (2024) и RFC 9980 (2026); GnuPG следует LibrePGP
Открытый ключ62 символа (age1…); постквантовый — 1959 символов (age1pq1…)Двоичный ключ с идентификаторами пользователя и самоподписями; 473 байта для пары Ed25519 и Cv25519 (измерено)
АлгоритмыX25519, гибрид ML-KEM-768 + X25519, scrypt для парольных фраз, ChaCha20-Poly1305, HKDF и HMAC-SHA-256Множество: RSA, ECC, AES, Camellia, устаревшие шифры для старых данных; ML-KEM-768 + X25519 в GnuPG 2.5
НастройкиНетПредпочтения, модели доверия, настройки алгоритмов и сжатия
Измеренный шифртекст для файла размером 26 байт226 байт (X25519); 1685 байт (постквантовый)203 байта (Cv25519); 1288 байт (подключ ML-KEM-768 + X25519)
Ключи SSH как получателиДа (ssh-ed25519, ssh-rsa)Нет
Аппаратные ключиЧерез плагины: YubiKey в режиме PIV, TPM, Secure EnclaveСмарт-карты OpenPGP и ключи безопасности
ПодписиНет, так задуманоДа
Поиск ключейНет; ключи получателей передаются напрямуюСерверы ключей, WKD, связки ключей
Большие файлыПотоковая обработка фрагментами по 64 КиБ с аутентификацией; API расшифрования с произвольным доступом начиная с версии 1.3Потоковая обработка; один AEAD-пакет с разбиением на фрагменты

Шифруем один и тот же файл обоими способами

Скрипт ниже шифрует секрет размером 26 байт для получателя age X25519, постквантового получателя age, подключа GnuPG Cv25519 и подключа GnuPG ML-KEM-768 + X25519, расшифровывает каждый результат и сравнивает размеры (age 1.3.2, GnuPG 2.5.21). Всё происходит во временном каталоге.

age и GnuPG: классические и постквантовые ключи
#!/bin/sh
dir=$(mktemp -d /tmp/agegpg.XXXXXX)   # short path: gpg-agent sockets need one
cd "$dir" || exit 1
export GNUPGHOME="$dir/g"
mkdir -m 700 g
printf 'db_password=correct-horse\n' > secret.env    # 26 bytes

echo "== age"
age-keygen -o key.txt 2> /dev/null
recipient=$(age-keygen -y key.txt)
echo "recipient: ${#recipient} characters"
age -r "$recipient" -o secret.env.age secret.env
age -d -i key.txt secret.env.age | cmp -s - secret.env && echo "decrypted: identical"
echo "ciphertext: $(wc -c < secret.env.age | tr -d ' ') bytes"

echo "== age, post-quantum recipient"
age-keygen -pq -o pq.txt 2> /dev/null
pqrecipient=$(age-keygen -y pq.txt)
echo "recipient: ${#pqrecipient} characters"
age -r "$pqrecipient" -o secret.env.pq.age secret.env
age -d -i pq.txt secret.env.pq.age | cmp -s - secret.env && echo "decrypted: identical"
echo "ciphertext: $(wc -c < secret.env.pq.age | tr -d ' ') bytes"

echo "== GnuPG"
gpg --batch --quiet --passphrase '' --quick-gen-key "Ops <ops@example.org>" ed25519 cert 1y
fpr=$(gpg --list-keys --with-colons ops@example.org 2> /dev/null | awk -F: '/^fpr/ { print $10; exit }')
gpg --batch --quiet --passphrase '' --quick-add-key "$fpr" cv25519 encr 1y
gpg --batch --quiet --trust-model always -r ops@example.org -o secret.env.gpg -e secret.env
gpg --batch --quiet -d secret.env.gpg 2> /dev/null | cmp -s - secret.env && echo "decrypted: identical"
echo "ciphertext: $(wc -c < secret.env.gpg | tr -d ' ') bytes"
echo "public key export: $(gpg --export ops@example.org | wc -c | tr -d ' ') bytes binary"

echo "== GnuPG, ML-KEM-768 + X25519 subkey"
gpg --batch --quiet --passphrase '' --quick-gen-key "Ops PQ <ops-pq@example.org>" ed25519 cert 1y
fpr=$(gpg --list-keys --with-colons ops-pq@example.org 2> /dev/null | awk -F: '/^fpr/ { print $10; exit }')
gpg --batch --quiet --passphrase '' --quick-add-key "$fpr" ky768_cv25519 encr 1y
gpg --batch --quiet --trust-model always -r ops-pq@example.org -o secret.env.pq.gpg -e secret.env
gpg --batch --quiet -d secret.env.pq.gpg 2> /dev/null | cmp -s - secret.env && echo "decrypted: identical"
echo "ciphertext: $(wc -c < secret.env.pq.gpg | tr -d ' ') bytes"
gpgconf --kill gpg-agent
cd / && rm -rf "$dir"
Результат
== age
recipient: 62 characters
decrypted: identical
ciphertext: 226 bytes
== age, post-quantum recipient
recipient: 1959 characters
decrypted: identical
ciphertext: 1685 bytes
== GnuPG
decrypted: identical
ciphertext: 203 bytes
public key export: 473 bytes binary
== GnuPG, ML-KEM-768 + X25519 subkey
decrypted: identical
ciphertext: 1288 bytes

Оба инструмента добавляют фиксированный заголовок на каждого получателя и небольшие накладные расходы на аутентификацию, поэтому для реальных файлов разница пренебрежимо мала. Постквантовые накладные расходы — это шифртекст ML-KEM-768 (1088 байт), который передаётся в блоке каждого получателя; у age они больше в основном потому, что его заголовок текстовый, а двоичные значения записаны в base64. Скрипт использует --trust-model always только потому, что ключ создан секундой раньше; в реальной работе вы проверили бы отпечаток ключа получателя.

Важные детали совместимости

gpg --list-packets для файлов выше показывает две вещи, которые стоит знать. Для ключа Cv25519 GnuPG 2.5 записывает пакет OCB «AEAD encrypted packet» в формате LibrePGP, а не пакет зашифрованных данных версии 2, который определён в RFC 9580, потому что собственные ключи GnuPG объявляют о поддержке такого пакета; реализации, которые следуют только RFC 9580, могут не прочитать такие файлы. Для постквантового подключа GnuPG использует алгоритм открытого ключа 8 — свою составную схему Kyber из LibrePGP, тогда как RFC 9980 отводит для ML-KEM-768 + X25519 номер 35, поэтому постквантовые ключи GnuPG и ключи по RFC 9980 несовместимы. У age один формат и одна постквантовая конструкция (HPKE с гибридом ML-KEM-768 и X25519, известным также как X-Wing), и для неё опубликованы тестовые векторы.

Почему age намеренно маленький

В age нет всего того, из-за чего OpenPGP трудно использовать безопасно: нет согласования алгоритмов, нет сжатия (которое может раскрывать сведения об открытом тексте), нет режима без аутентификации, нет сервера ключей и нет сети доверия. Получатель — это строка, которую можно вставить в файл конфигурации, а в файле, зашифрованном для нескольких получателей, на каждого получателя приходится один блок. Цена — узкий круг задач: age не умеет подписывать, поэтому не доказывает, кто зашифровал файл, а также не управляет ключами и не распространяет их. Эти пробелы закрывают инструменты вокруг него: SOPS шифрует значения в YAML и JSON для получателей age, а плагины позволяют хранить закрытые ключи на YubiKey, в TPM или в Secure Enclave macOS.

Широта GnuPG ценна там, где OpenPGP — общий язык: подписанная и зашифрованная почта с теми, с кем вы уже переписываетесь, репозитории пакетов, подписи релизов, которые уже проверяют потребители ниже по цепочке, и смарт-карты OpenPGP, на которых вместе хранятся ключи подписи, шифрования и аутентификации.

Что когда выбирать

  • Секреты в Git (SOPS), переменные CI, резервные копии, dotfiles: age, по одному получателю на каждого человека или машину плюс аппаратный или офлайн-получатель для восстановления.
  • Шифрование для уже имеющегося у вас ключа SSH другого человека: age.
  • Долгосрочные конфиденциальные архивы: age с постквантовыми получателями age1pq1, чтобы противостоять стратегии «собери сейчас, расшифруй потом».
  • Зашифрованная почта: OpenPGP (или S/MIME, см. S/MIME или OpenPGP).
  • Шифрование и подпись за один шаг для получателя, который пользуется OpenPGP: GnuPG.
  • Подписи релизов и пакетов: ни age, ни GPG в роли инструмента шифрования; см. Sigstore или GPG.

Заметки о миграции

  1. Сгенерируйте закрытые ключи age для каждого человека или машины (age-keygen или age-keygen -pq, когда все, кто шифрует или расшифровывает, перейдут на age 1.3 или новее) и храните закрытый ключ для восстановления офлайн.
  2. Перешифровывайте, а не конвертируйте: расшифруйте каждый файл GPG старым ключом и зашифруйте для новых получателей; преобразования формата не существует. Для SOPS добавьте получателей age в правила создания (creation rules) в .sops.yaml и выполните sops updatekeys для каждого файла; когда позже будете удалять ключи PGP, выполните после этого sops rotate, чтобы сменился и ключ данных.
  3. Сохраните ключ GPG, пока все старые файлы и резервные копии не будут перешифрованы или пока не истечёт срок их хранения.
  4. Замените подписи GPG отдельно подписями SSH, minisign или Sigstore: age подписей не создаёт.
  5. Проверьте размеры и инструменты с помощью инструмента шифрования age и изучите старые файлы в инспекторе OpenPGP, чтобы узнать, какие ключи и алгоритмы в них используются.

Источники

Все сравнения