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

GnuPG (gpg)

GnuPG 2.4 — реализация OpenPGP, на которой работает gpg: ключи Ed25519, срок действия которых по умолчанию истекает через три года, детерминированный ECDSA по RFC 6979 на кривых NIST, Brainpool и secp256k1, подписи Ed25519 от дайджеста и пока никаких постквантовых алгоритмов.
Лицензия
GPL-3.0-or-later
Проверенная версия
2.4.9 ·
Исходный код
dev.gnupg.org/source/gnupg/
Документация
www.gnupg.org/documentation/manuals/gnupg/

Совместимость вкратце

ECDSAEdDSA

Кривые ECDSA
P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1
EdDSA
Ed25519Ed448

GnuPG реализует OpenPGP для подписи и шифрования файлов и почты, подписи пакетов во многих дистрибутивах Linux и подписи коммитов git. Факты на этой странице проверены на пакете Alpine 3.24.2: GnuPG 2.4.9 с libgcrypt 1.12.2. gpg --quick-gen-key с одним только идентификатором пользователя создаёт основной ключ Ed25519 для подписи и сертификации и подключ шифрования Curve25519 (cv25519), оба как ключи версии 4, а срок действия основного ключа истекает через 1095 дней (три года), если срок не задан явно. Разбирайте ключи и подписи в инспекторе OpenPGP.

Ключи ECDSA можно создавать на P-256, P-384, P-521, secp256k1 и трёх кривых Brainpool r1; nistp224 завершается ошибкой «Unknown elliptic curve». Пакет подписи содержит r и s как два MPI OpenPGP — это не DER и не r‖s фиксированной длины. Подписи P-256 по умолчанию используют SHA-256; запрос SHA-256 для ключа P-384 завершается ошибкой «signing failed: Invalid length», а SHA-512 с ключом P-256 принимается.

Nonce детерминированные: при зафиксированных часах (--faked-system-time) две подписи одного файла совпали байт в байт, а r совпало с результатом независимой реализации RFC 6979, поэтому повторная подпись тех же данных не приводит к опасному повторному использованию nonce. Значение s не нормализуется, и подпись, в которой s заменили на n − s, была признана верной — это важно везде, где от подписей ожидается уникальность.

Подписи Ed25519 используют устаревший формат EdDSA (алгоритм 22): R и S хранятся как MPI, а Ed25519 подписывает не сам файл, а дайджест SHA-512 от файла и хешируемых полей подписи. Подпись R‖S, в которой каждое значение дополнено слева до 32 байт, прошла проверку в OpenSSL по этому дайджесту и не прошла по самому файлу, поэтому для проверки подписей gpg библиотекой Ed25519 общего назначения сначала нужно вычислить дайджест OpenPGP. Ключи Ed448 создаются как пакеты ключей версии 5 в формате черновика LibrePGP, которому следует GnuPG, тогда как ключи по умолчанию, ключи ECDSA и ключи Ed25519 в проверке были версии 4; прежде чем выбирать Ed448, убедитесь, что другая сторона читает версию 5. В этом выпуске нет ни одного постквантового алгоритма: в списке алгоритмов с открытым ключом — RSA, ELG, DSA, ECDH, ECDSA и EDDSA, а ky768_cv25519 отклоняется как неизвестная кривая.

В скриптах читайте машиночитаемый вывод --status-fd, а не текст: для верной подписи gpg выдал GOODSIG и VALIDSIG с кодом завершения 0, для подписи других данных — BADSIG с кодом завершения 1, а для обрезанного пакета — NODATA с кодом завершения 2. gpg --export-ssh-key с отпечатком и ! записывает для ключей ECDSA и Ed25519 строку открытого ключа OpenSSH, а --export и --export-secret-keys записывают пакеты OpenPGP.

Факты и проверки, на которых они основаны

Ничего из приведённого ниже не скопировано из документации. 20 октября 2026 г. проверка content/libraries/verify/gnupg/run.sh запустила GnuPG (gpg) 2.4.9 в образе контейнера alpine:3.24.2; содержимое страницы должно совпадать с выводом проверки, а у каждого факта приведены соответствующие строки вывода.

  • Тип ключа по умолчанию

    ed25519cv25519

    --quick-gen-key с одним только идентификатором пользователя создал основной ключ ed25519 (назначение sc) и подключ cv25519 (назначение e).

    Что записала проверка
    fact default-key-type = ed25519, cv25519
    evidence default-key-type: pub ed25519 (algorithm 22, usage scESC); sub cv25519 (algorithm 18, usage e)
  • Срок действия ключа по умолчанию

    1095d

    Срок действия основного ключа истекал через 1095 дней после его создания.

    Что записала проверка
    fact default-key-expiry = 1095d
    evidence default-key-expiry: expiration minus creation of the primary key: 1095 days
  • Версия ключа OpenPGP

    v4

    Ключ по умолчанию экспортировался как пакет ключа версии 4.

    Что записала проверка
    fact openpgp-key-version = v4
  • Версия ключа Ed448

    v5

    Ключ ed448 экспортировался как пакет ключа версии 5, а ключ по умолчанию и ключи ECDSA и ed25519 — как пакеты версии 4.

    Что записала проверка
    fact ed448-key-version = v5
    evidence ed448-key-version: key packet versions: default v4, nistp256 v4, nistp384 v4, nistp521 v4, secp256k1 v4, brainpoolP256r1 v4, brainpoolP384r1 v4, brainpoolP512r1 v4, ed25519 v4, ed448 v5
  • Кривые ECDSA

    P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1

    На всех семи кривых созданы ключи, с которыми подпись и проверка работают; nistp224 вернул «Unknown elliptic curve».

    Что записала проверка
    fact ecdsa-curves = P-256, P-384, P-521, secp256k1, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1
    evidence ecdsa-curves: nistp224: gpg: Key generation failed: Unknown elliptic curve
  • EdDSA

    Ed25519Ed448

    Подпись и проверка работают с ключами ed25519 и ed448.

    Что записала проверка
    fact eddsa = Ed25519, Ed448
  • Постквантовые алгоритмы

    none

    В строке Pubkey: вывода gpg --version нет ни одного постквантового алгоритма, а генерация ключа ky768_cv25519 завершилась ошибкой.

    Что записала проверка
    fact pqc = none
    evidence pqc: --quick-gen-key with ky768_cv25519: gpg: Key generation failed: Unknown elliptic curve
  • Кодировка подписи ECDSA

    openpgp-mpi

    Пакет подписи P-256 (алгоритм 19) заканчивается двумя MPI: r и s.

    Что записала проверка
    fact ecdsa-signature-encoding = openpgp-mpi
    evidence ecdsa-signature-encoding: P-256 detached signature: version=4 pubkey-algo=19 hash-algo=8 mpis=2
  • Хеш-функция по умолчанию

    sha256

    В подписи P-256 по умолчанию указан хеш-алгоритм 8, то есть SHA-256.

    Что записала проверка
    fact ecdsa-default-hash = sha256
  • Nonce в ECDSA

    rfc6979

    Две подписи при зафиксированных часах совпали, а r совпало с эталонной реализацией подписи по RFC 6979.

    Что записала проверка
    fact ecdsa-nonce = rfc6979
    evidence ecdsa-nonce: two signatures of one file with a frozen clock are identical; r equals the RFC 6979 reference signer's r: yes
  • Low-S при подписи

    either

    Значение s не нормализуется: среди 32 подписей встретились значения high-S.

    Что записала проверка
    fact ecdsa-low-s-sign = either
    evidence ecdsa-low-s-sign: signatures with s > n/2 among 32: yes
  • High-S при проверке

    accepts-high-s

    Подпись, в которой s заменили на n − s, прошла проверку: GOODSIG и код завершения 0.

    Что записала проверка
    fact ecdsa-low-s-verify = accepts-high-s
    evidence ecdsa-low-s-verify: s replaced by n - s: exit 0, status NEWSIG KEY_CONSIDERED SIG_ID GOODSIG VALIDSIG TRUST_ULTIMATE
  • Хеш-функция, привязанная к кривой

    enforced

    --digest-algo SHA256 с ключом P-384 завершился ошибкой «Invalid length», а с SHA-512 ключ P-256 подписал успешно.

    Что записала проверка
    fact ecdsa-hash-curve-binding = enforced
    evidence ecdsa-hash-curve-binding: --digest-algo SHA256 with a P-384 key: gpg: signing failed: Invalid length; --digest-algo SHA512 with a P-256 key: signed
  • Вывод проверки при ошибке

    distinguishable

    BADSIG и код завершения 1 для другого сообщения; NODATA и код завершения 2 для обрезанного пакета.

    Что записала проверка
    fact cli-verify-output = distinguishable
    evidence cli-verify-output: valid: exit 0, status NEWSIG KEY_CONSIDERED SIG_ID GOODSIG VALIDSIG TRUST_ULTIMATE
    evidence cli-verify-output: wrong message: exit 1, status NEWSIG KEY_CONSIDERED BADSIG FAILURE
    evidence cli-verify-output: truncated signature packet: exit 2, status NODATA FAILURE
  • Что охватывает подпись Ed25519

    digest

    Подпись R‖S прошла проверку в openssl pkeyutl по дайджесту подписи OpenPGP и не прошла по самому файлу.

    Что записала проверка
    fact ed25519-signed-input = digest
    evidence ed25519-signed-input: version=4 pubkey-algo=22 hash-algo=10 mpis=2; R || S checked by openssl pkeyutl over the signature digest: Signature Verified Successfully; over the file: Signature Verification Failure
  • Форматы открытых ключей

    opensshopenpgp

    gpg --export записывает пакеты OpenPGP; --export-ssh-key записал строки ecdsa-sha2-nistp256 и ssh-ed25519.

    Что записала проверка
    fact public-key-formats = openssh, openpgp
    evidence public-key-formats: gpg --export: public key packet; gpg --export-ssh-key: P-256 key ecdsa-sha2-nistp256, Ed25519 key ssh-ed25519
  • Форматы закрытых ключей

    openpgp

    gpg --export-secret-keys записывает пакеты секретных ключей OpenPGP.

    Что записала проверка
    fact private-key-formats = openpgp
    evidence private-key-formats: gpg --export-secret-keys: secret key packet

Использование

Создайте ключ по умолчанию, сделайте отсоединённую подпись в формате ASCII armor и проверьте её по выводу статуса.
export GNUPGHOME="$(mktemp -d)"
# With only a user ID: an Ed25519 signing key plus a Curve25519 encryption subkey, expiring in 3 years.
gpg --batch --pinentry-mode loopback --passphrase '' --quick-gen-key 'Alice <alice@example.com>'

printf 'order #1042 approved\n' > order.txt
gpg --batch --yes --armor --detach-sign order.txt   # writes order.txt.asc

# Scripts should read --status-fd: GOODSIG and VALIDSIG for a valid signature, BADSIG otherwise.
gpg --batch --status-fd 1 --verify order.txt.asc order.txt 2>/dev/null | grep -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)' | cut -d' ' -f2

Тестовый стенд для фрагментов кода запускает каждый пример без изменений в образе контейнера alpine:3.24.2, и запуск завершается ошибкой, если вывод не совпадает.

Подготовка
apk add --no-cache -q gnupg=2.4.9-r1 >/dev/null
Команда
sh sign.sh
Вывод должен совпадать (регулярное выражение)
GOODSIG\nVALIDSIG

Библиотеки