43

Is there a way via an CLI tool or some kind of API to extract the PGP key ID from the PGP public key block?

I found the hexa value of the key in the binary file, but I guess the position is based on the key kind/size.

Basically, I have the base64 formatted public key and I would like to retrieve the key ID from it, without importing it with GnuPG.

7 Answers 7

15

RFC 4880 on OpenPGP message format talks about how to calculate key ID from public key.

Excerpts from section 12.2:

For a V3 key, the eight-octet Key ID consists of the low 64 bits of the public modulus of the RSA key.

And for V4 keys:

A V4 fingerprint is the 160-bit SHA-1 hash of the octet 0x99, followed by the two-octet packet length, followed by the entire Public-Key packet starting with the version field. The Key ID is the low-order 64 bits of the fingerprint.

You can easily parse the last 64 bits from the base64 encoded public keys, which is the key ID for the corresponding public key.

1
  • 5
    could you please elaborate more on "easily parse the last 64 bits..."? I generated a pgp key (Got its MPI in base64 format. Is it what is meant by public key?), copy-n-pasted it to here, for example, and counted last 8 bytes in hex representation. Is that correct? Commented Mar 27, 2015 at 14:50
27

You can use gpg --dry-run to prevent changes.

Following line will print the key id in its output (can be modified using the usual modifiers like --with-colons for further processing). A4FF2279 is the key ID in here.

$ gpg --dry-run --import pubkey.asc
gpg: key A4FF2279: public key "[User ID not found]" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
gpg: no ultimately trusted keys found

Just tried it, the key did not get stored to my keychain, but the key ID was printed. But watch out with --dry-run, the man page has a warning:

   --dry-run
         Don't make any changes (this is not completely implemented).

A more in-depth discussion of multiple variants for human-readable, machine-readable and very technical output for different versions of GnuPG is found in the Stack Overflow question How to display gpg key details without importing it?. All of them will also present the key ID.

4
  • 2
    Would be nice, if you could update your answer mentioning the --import --import-options show-only, which seams to be the cleanest solution (regarding the not completely implemented problem), like you already did here: How to display gpg key details without importing it?
    – Murmel
    Commented Nov 5, 2018 at 14:19
  • Instead of duplicating the whole answer I went for a hotlink.
    – Jens Erat
    Commented Nov 24, 2018 at 7:00
  • 4
    I had to add --verbose to have it print the ID/email. (First I also had to create the .gpg directory in $HOME - not sure if that's a WSL/Ubuntu quirk or what.) Commented Dec 29, 2019 at 14:52
  • @Murmel: gpg --import --import-options show only doesn't work with GPG 1.416.
    – pts
    Commented Apr 30, 2020 at 10:43
25

From the gpg manual (gpg (GnuPG) 2.2.11):

--show-keys

This commands takes OpenPGP keys as input and prints information about them in the same way the command --list-keys does for locally stored key. In addition the list options show-unusable-uids, show-unusable-subkeys, show-notations and show-policy-urls are also enabled. As usual for automated processing, this command should be combined with the option --with-colons.

For instance:

$ gpg --show-keys docker-ce.gpg
pub   rsa4096 2017-02-22 [SCEA]
      9DC858229FC7DD38854AE2D88D81803C0EBFCD88
uid                      Docker Release (CE deb) <[email protected]>
sub   rsa4096 2017-02-22 [S]

where 9DC858229FC7DD38854AE2D88D81803C0EBFCD88 is the key id.

2
  • 2
    Earlier versions of GPG, e.g. 2.1.18 don't have --show-keys.
    – pts
    Commented Apr 30, 2020 at 10:37
  • 1
    @pts For them its --import-options show-only --import.
    – Suuuehgi
    Commented Mar 4 at 15:35
5
gpg --with-fingerprint GPG-KEY-filename-that-you-downloaded-from-internet

For example :

wget https://artifacts.elastic.co/GPG-KEY-elasticsearch
gpg --with-fingerprint GPG-KEY-elasticsearch
4
  • 4
    can you expand this answer with what the command argument does and the output from that key?
    – schroeder
    Commented Nov 9, 2017 at 12:15
  • 2
    command missing
    – chefarov
    Commented Mar 26, 2018 at 14:28
  • I.e.: If you like to validate a downloaded Oracle Java RPM package, you may check the package via rpm -qip <RPM> | grep -i signature and check the key via gpg --with-fingerprint RPM-GPG-KEY-ORACLE. You will find as output Signature : RSA/SHA256, Sat 06 Oct 2018 03:29:42 PM WEST, Key ID 72f97b74ec551f03 and pub 2048R/EC551F03 2010-07-01 Oracle OSS group (Open Source Software group) <[email protected]> Key fingerprint = 4214 4123 FECF C55B 9086 313D 72F9 7B74 EC55 1F03. As you can see, Key ID 72f9 7b74 ec55 1f03 fits to the fingerprint.
    – U880D
    Commented Dec 3, 2018 at 12:54
  • 1
    gpg --with-fingerprint FILENAME works with GPG 1.4.16, but it doesn't work with GPG 2.1.18.
    – pts
    Commented Apr 30, 2020 at 10:41
3

To get the key IDs (8 bytes, 16 hex digits), this is the command which worked for me in GPG 1.4.16, 2.1.18 and 2.2.19:

gpg --list-packets <key.asc | awk '$1=="keyid:"{print$2}'

To get some more information (in addition to the key ID):

gpg --list-packets <key.asc

To get even more information:

gpg --list-packets -vvv --debug 0x2 <key.asc

The command

gpg --dry-run --keyid-format long --import <key.asc

also works in all 3 versions, but in GPG 2.1.18 it prints the key ID of the main key only (and not the subkeys), and in 1.4.16 it prints both the main keys and the subkeys.

Commands in other answers (e.g. gpg --show-keys, gpg --with-fingerprint, gpg --import --import-options show-only) don't work in some of the 3 GPG versions above, thus they are not portable when targeting multiple versions of GPG.

3
  • 1
    gpg 1 defaults to short keyid but you can specify (or configure in gpg.conf) --keyid-format=long Commented May 1, 2020 at 1:50
  • @dave_thompson_085: Thank you for proposing --keyid-format long. I've added it to my answer. However. I strill don't recommend using gpg --dry-run --import because of inconsistencies in subkey key ID reporting among GPG versions. I've also added this to my answer.
    – pts
    Commented May 1, 2020 at 22:28
  • 1
    gpg version 2.2.40 only outputs gpg: Total number processed: 1 (and nothing else) on the last command gpg --dry-run --keyid-format long --import <key.asc. Also gpg -vvv --list-packets does not contain the long key ID (which I need). And gpg --keyid-format long --show-keys < key outputs something which cannot be parsed without using some very crude heuristics, which is very likely to fail in some not-so-distant future. Out of luck?
    – Tino
    Commented Apr 7 at 16:17
1

After the public key has been imported

pgp --import PublicKeyToImport.asc

run

pgp --list-userids

to determine the key or User ID to be used with --encrypt.

Alg  Type Size/Type Flags   Key ID     User ID
---- ---- --------- ------- ---------- -------
1
  • 2
    The question explicitly asks for a solution without importing the key. This answer doesn't answer the question.
    – pts
    Commented Apr 30, 2020 at 10:38
0

FWIW: With gpg version 2.2.40 from Debian stable I needed following:

  • Extract the long ID of some public keyfile which may be downloaded and not yet installed
  • It must not try to access $HOME/.gnupg/ as this triggers a kill -9 from AppArmor
  • It must not try to open anything for write, as this triggers a kill -9 by AppArmor

This is what I came up with:

KEY=key.asc
cat "$KEY" |

LC_ALL=C GNUPGHOME=/I/G/N/O/R/E/ gpg --no-options --dry-run --show-keys --keyid-format long --import-options show-only 2>/dev/null |
awk '/^pub/ { trig=1; next } trig { print $1; trig=0 }' |

cat

This can be used for example to verify the Docker key like this (in bash):

curl -s https://download.docker.com/linux/debian/gpg |
tee /tmp/docker.key |

LC_ALL=C GNUPGHOME=/I/G/N/O/R/E/ gpg --no-options --dry-run --show-keys --keyid-format long --import-options show-only 2>/dev/null |
awk '/^pub/ { trig=1; next } trig { print $1; trig=0 }' |

cmp - <(echo 9DC858229FC7DD38854AE2D88D81803C0EBFCD88)

echo $?

or a bit less readable, but this uses a few less system resources:

<<<9DC858229FC7DD38854AE2D88D81803C0EBFCD88 cmp <(
curl -s https://download.docker.com/linux/debian/gpg |
tee /tmp/docker.key |
LC_ALL=C GNUPGHOME=/I/G/N/O/R/E/ gpg --no-options --dry-run --show-keys --keyid-format long --import-options show-only 2>/dev/null |
awk '/^pub/ { trig=1; next } trig { print $1; trig=0 }'
)

echo $?

Notes:

  • cat "$KEY" is the placeholder for the producer which outputs the key

  • cat is the placeholder for the consumer which checks the ID

  • The echo $? are for example purpose and will report 0 if verification was successful.
    Usually you would wrap the block before the echo in an if or use something like || err verification failed or similar.

  • I am not sure, though, that this is the right approach, as the gods of gpg might certainly change the output in future. So this probably can or must be improved. YMMV.

  • You can use /dev/null instead of /I/G/N/O/R/E/, but then gpg spits out 2 lines of error instead of 1. Hence the 2>/dev/null

  • I was not able to stop gpg from failing when there is some wrong system wide configuration in place. For example after sudo mkdir -p /etc/gnupg/gpg.conf it even enters a 100% CPU endless loop and never comes back unless killed explicitly. You won't see it because of the 2>/dev/null which is needed to silence some other ugly errors gpg spits out in case that /I/G/N/O/R/E/pubring.kbx does not exist.

Note that I tried to report the endless loop as bug to GnuPG. But the process of telling them bugs was too complicated for me, hence I was not able to do so. Instead I submitted this to Debian Bugs. Sorry.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .