Вопрос или проблема
Если я выполняю gpg foo.gpg
, мне показывается диалоговое окно, которое выглядит следующим образом:
┌────────────────────────────────────────────────────────────────┐
│ Пожалуйста, введите парольную фразу, чтобы разблокировать секре… │
│ ключ OpenPGP: "Edward A. Falk <[email protected]>" │
│ 1024-битный ELG ключ, ID xxxxxxxxxxxxxxxx, │
│ │
│ │
│ Парольная фраза: _____________________________________________ │
│ │
│ <ОК> <Отмена> │
└────────────────────────────────────────────────────────────────┘
и все работает просто отлично.
Если я выполняю cat foo.gpg | gpg
, я получаю
gpg: ошибка расшифровки публичного ключа: Неподходящий ioctl для устройства
Я пробовал --passphrase-fd 0
и --batch --pinentry-mode loopback
, но безрезультатно. Мне удалось заставить это работать, указав парольную фразу в командной строке, но я действительно хочу этого избежать, если можно.
Я подозреваю, что это как-то связано с агентом pinentry, но я не совсем понимаю, как управлять агентом. (Я действительно не знаю, почему gpg вообще его требуется.)
Я использую gpg 2.2.26.
Одно небольшое пояснение: мой стандартный ввод на самом деле не поступает из “cat foo.gpg”; это больше похоже на aws s3 cp "s3://myawsbucket.tar.gz.gpg" -
, где именованный бакет значительно больше, чем я хочу хранить на моем локальном компьютере, только чтобы расшифровать его и извлечь из него всего один файл.
Я выяснил, что мне нужно сделать по-другому. Оказалось, что если gpg-agent работает и правильно настроен, все будет работать. gpg-agent знает, как взаимодействовать с пользователем для получения парольной фразы. Дополнительную информацию смотрите в man-странице gpg-agent.
Ответ или решение
Причина возникновения ошибки "public key decryption failed: Inappropriate ioctl for device" при использовании команды gpg
заключается в разнице работы механизмов обработки ввода/вывода данных в команде. Давайте рассмотрим основные аспекты, объясняющие, почему возникает эта ошибка и как ее можно устранить.
Теория
Ошибка "Inappropriate ioctl for device" связана с тем, что при использовании команды cat foo.gpg | gpg
ввод данных для gpg осуществляется через пайп. В такой конфигурации gpg ожидает данные с stdin, но не может получить доступ к терминальному устройству для запроса пароля. Когда gpg
запускается с файла, он имеет доступ к терминалу и может корректно запросить у пользователя ввод пароля через интерфейс pinentry, который используется агентом gpg.
GPG (GNU Privacy Guard) — это инструмент с открытым исходным кодом для шифрования и дешифрования данных, который использует различные криптографические алгоритмы. Поскольку многие команды Linux взаимодействуют с файлом или устройствами, GPG использует свою отдельную утилиту — gpg-agent — для управления вводом/выводом паролей.
Когда gpg-agent активен и правильно настроен, он обрабатывает запросы к пользователю о вводе пароля, независимо от того, как именно происходит запуск команды. В данном случае, отсутствие корректной настройки или работа gpg-agent может привести к тому, что gpg не может запросить пароль и соответственно выдает ошибку.
Пример
Вы можете запускаете следующую команду для дешифровки файла, используя stdin:
aws s3 cp "s3://myawsbucket.tar.gz.gpg" - | gpg
В результате возникает ошибка:
gpg: public key decryption failed: Inappropriate ioctl for device
Это связано с тем, что GPG не может получить доступ к терминальному устройству для запроса ввода пароля через стандартный PGP интерфейс, управляющийся gpg-agent.
Применение
Для решения этой проблемы необходимо следующее:
-
Активировать и настроить gpg-agent. Убедитесь, что gpg-agent запущен и правильным образом настроен. Для активации можете использовать команду:
gpgconf --launch gpg-agent
-
Настроить файл конфигурации. Проверьте или создайте файл
~/.gnupg/gpg-agent.conf
, чтобы он содержал:pinentry-program /usr/bin/pinentry allow-loopback-pinentry
-
Перезапустить gpg-agent. После внесения изменений, агент необходимо перезапустить:
gpgconf --kill gpg-agent gpgconf --launch gpg-agent
-
Использовать –pinentry-mode=loopback. Теперь можете использовать ключи параметров для gpg:
aws s3 cp "s3://myawsbucket.tar.gz.gpg" - | gpg --pinentry-mode=loopback --decrypt
Оператор
--pinentry-mode=loopback
позволяет gpg использовать loopback для интерактивных запросов пароля через stdin, причем при этом активность gpg-agent остается необходимой, чтобы он обрабатывал все необходимые вызовы и не блокировал выполнение программы.
Настройка gpg-agent позволяет вам обрабатывать неудобные ситуации с вводом, например, когда stdin не может предоставить привычный набор команд для ввода пароля. Описанное решение позволит вам дешифровать файлы, которые не были скачаны локально полностью, с применением оболочки, что весьма важно в случае работы с большими объемами данных, например, в облачных средах.
Этот подход позволяет сохранять высокий уровень безопасности, недопуская ввод пароля через командную строку, что не рекомендуется из соображений безопасности. Надеюсь, что эта информация будет полезна и поможет устранить проблемы, связанные с дешифровкой файлов через gpg с использованием промежуточного пайплайна данных.