# Why is GnuPG changing first two characters of ascii armored public key after downloading it from the key server?

When I look at my public key on the key server, the first two characters of the ASCII-Armored data section (as defined in section 6.2 of RFC 4880, which defines the structure of the ASCII-Armored OpenPGP Message Format) differ from the first to characters of the public key as viewed from my terminal after downloading the key with the gpg command.

Here is the key as it appears on the key server:

And a transcription of the key itself:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: FlowCrypt [BUILD_REPLACEABLE_VERSION] Gmail Encryption
Comment: Seamlessly send and receive encrypted email

xjMEXtkufxYJKwYBBAHaRw8BAQdAEumP9mQ4J2WwxvobXB83FleS7rzAMiVB
pnm0aXiH3zPNJ0FsZWphbmRybyBBbHZhcmFkbyA8YWxleEBmbG93Y3J5cHQu
Y29tPsJ4BBAWCgAgBQJe2S5/BgsJBwgDAgQVCAoCBBYCAQACGQECGwMCHgEA
CgkQM8Ds7LiIxBl/5gEAiAmBnaA9gqy9DnlmWneBLXokjh8w0YxrF9L/Pn/b
f5IBAIC2DeFZjCGqtkYhjqboHjYrik1NsZQjJTkUOEksDxcIzjgEXtkufxIK
KwYBBAGXVQEFAQEHQCn3uPFsdPiffwNwXVl8ybf5vuruvi42Bh6XISO62ody
AwEIB8JhBBgWCAAJBQJe2S5/AhsMAAoJEDPA7Oy4iMQZMC8A/jJguhTkVhvP
agLK7e/IbDlLpZ1Eq+1EHXr77WnluR/sAP9AN818MJ9dBD1yo6XoYHQRG9uA
W5AW/xP5Tr+Y6Z8eAg==
=wujj
-----END PGP PUBLIC KEY BLOCK-----


Source: key server

The first two characters of the data section are xj.

Now I will download and display the key using the gpg command:

➜  ~ rm -rf .gnupg
➜  ~ gpg --keyserver attester.flowcrypt.com --recv-keys 33C0ECECB888C419
gpg: directory '/home/alex/.gnupg' created
gpg: keybox '/home/alex/.gnupg/pubring.kbx' created
gpg: /home/alex/.gnupg/trustdb.gpg: trustdb created
gpg: key 33C0ECECB888C419: public key "Alejandro Alvarado <alex@flowcrypt.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1
➜  ~ gpg --export --armor alex@flowcrypt.com
-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEXtkufxYJKwYBBAHaRw8BAQdAEumP9mQ4J2WwxvobXB83FleS7rzAMiVBpnm0
aXiH3zO0J0FsZWphbmRybyBBbHZhcmFkbyA8YWxleEBmbG93Y3J5cHQuY29tPoh4
BBAWCgAgBQJe2S5/BgsJBwgDAgQVCAoCBBYCAQACGQECGwMCHgEACgkQM8Ds7LiI
xBl/5gEAiAmBnaA9gqy9DnlmWneBLXokjh8w0YxrF9L/Pn/bf5IBAIC2DeFZjCGq
tkYhjqboHjYrik1NsZQjJTkUOEksDxcIuDgEXtkufxIKKwYBBAGXVQEFAQEHQCn3
uPFsdPiffwNwXVl8ybf5vuruvi42Bh6XISO62odyAwEIB4hhBBgWCAAJBQJe2S5/
AhsMAAoJEDPA7Oy4iMQZMC8A/jJguhTkVhvPagLK7e/IbDlLpZ1Eq+1EHXr77Wnl
uR/sAP9AN818MJ9dBD1yo6XoYHQRG9uAW5AW/xP5Tr+Y6Z8eAg==
=crYM
-----END PGP PUBLIC KEY BLOCK-----


(note that 33C0ECECB888C419 is the key's long id on the key server)

We see a key that looks mostly similar, with two exceptions. One disparity is expected: the Armor Checksum. That is the part at the end of the key that looks like =crYM (in the second example key displayed by the gpg command) or =wujj (in the first example from my key server). This part is not a mystery, and is answered in another StackExchange question here: https://security.stackexchange.com/questions/191626/gpg-armor-export-secret-key-differ-on-last-4-characters

I am interested in the other discrepancy, the first two characters of the data section. In the key as displayed by my key server, the two characters are xj. In the key as displayed by the gpg --export --armor <email> command, the two characters are mD.

Blaming this on my key server also occurred to me. Perhaps this is an issue with FlowCrypt's Attester key server. So I went to Wikipedia's list of notable public key servers and selected the first example from the list, https://keys.openpgp.org.

-----BEGIN PGP PUBLIC KEY BLOCK-----

xjMEXtkufxYJKwYBBAHaRw8BAQdAEumP9mQ4J2WwxvobXB83FleS7rzAMiVBpnm0
aXiH3zPNJ0FsZWphbmRybyBBbHZhcmFkbyA8YWxleEBmbG93Y3J5cHQuY29tPsJ4
BBAWCgAgBQJe2S5/BgsJBwgDAgQVCAoCBBYCAQACGQECGwMCHgEACgkQM8Ds7LiI
xBl/5gEAiAmBnaA9gqy9DnlmWneBLXokjh8w0YxrF9L/Pn/bf5IBAIC2DeFZjCGq
tkYhjqboHjYrik1NsZQjJTkUOEksDxcIzjgEXtkufxIKKwYBBAGXVQEFAQEHQCn3
uPFsdPiffwNwXVl8ybf5vuruvi42Bh6XISO62odyAwEIB8JhBBgWCAAJBQJe2S5/
AhsMAAoJEDPA7Oy4iMQZMC8A/jJguhTkVhvPagLK7e/IbDlLpZ1Eq+1EHXr77Wnl
uR/sAP9AN818MJ9dBD1yo6XoYHQRG9uAW5AW/xP5Tr+Y6Z8eAg==
=wujj
-----END PGP PUBLIC KEY BLOCK-----


Observe that the first two characters are xj. The rest of the key is also identical to how it appears on FlowCrypt's Attester. Now I will download and export the key from OpenPGP's key server using the gpg command line tool, just like I did with the Attester before:

➜  ~ gpg --keyserver keys.openpgp.org --recv-keys 33C0ECECB888C419gpg: directory '/home/max/.gnupg' created
gpg: keybox '/home/max/.gnupg/pubring.kbx' created
gpg: /home/max/.gnupg/trustdb.gpg: trustdb created
gpg: key 33C0ECECB888C419: public key "Alejandro Alvarado <alex@flowcrypt.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1

➜  ~ gpg --export --armor alex@flowcrypt.com
-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEXtkufxYJKwYBBAHaRw8BAQdAEumP9mQ4J2WwxvobXB83FleS7rzAMiVBpnm0
aXiH3zO0J0FsZWphbmRybyBBbHZhcmFkbyA8YWxleEBmbG93Y3J5cHQuY29tPoh4
BBAWCgAgBQJe2S5/BgsJBwgDAgQVCAoCBBYCAQACGQECGwMCHgEACgkQM8Ds7LiI
xBl/5gEAiAmBnaA9gqy9DnlmWneBLXokjh8w0YxrF9L/Pn/bf5IBAIC2DeFZjCGq
tkYhjqboHjYrik1NsZQjJTkUOEksDxcIuDgEXtkufxIKKwYBBAGXVQEFAQEHQCn3
uPFsdPiffwNwXVl8ybf5vuruvi42Bh6XISO62odyAwEIB4hhBBgWCAAJBQJe2S5/
AhsMAAoJEDPA7Oy4iMQZMC8A/jJguhTkVhvPagLK7e/IbDlLpZ1Eq+1EHXr77Wnl
uR/sAP9AN818MJ9dBD1yo6XoYHQRG9uAW5AW/xP5Tr+Y6Z8eAg==
=crYM
-----END PGP PUBLIC KEY BLOCK-----


Again, we see that GPG sets the first two characters to mD. I am quite befuddled by this mysterious behavior.

Why is gpg doing this? Does anyone know why the first two characters of the public key would be altered when I use the gpg command to display a key?

• What I'm entirely missing here is you trying to fall back on the standard documents for PGP. Always look up the standard if something like this is unclear. They usually contain the best description. Jul 5 '20 at 12:04

The public key follows the OpenPGP message format.

The part inside the -----…----- blocks, apart from the headers, is encoded in base64 (the OpenPGP specification calls it Radix-64). If you decode it, you'll see that only the first byte of the data changes: mDME decodes to 0x98 0x33 0x04 while xjME decodes to 0xc6 0x33 0x04.

The data that's encoded in Base64 is a sequence of OpenPGP packets. The first byte of a packet is its tag. There are two formats for the tag: the old format and the new format. Bit 6 (i.e. the next-to-most significant bit) determines the packet format: 0 for old, 1 for new.

0x98 = 0b10011000 is an old-format packet tag, where bits 0–1 (0b00 = 0) indicate the length type and bits 2–5 (0b0110 = 6) indicate the packet type. With a length type of 0, the length is expressed as one byte, which is the next byte 0x33.

0xc6 = 0b11000110 is a new-format packet tag, where bits 0–5 (0b000110 = 6) indicate the packet type. The next byte has a value 0x33 = 51 that's less than 192 so it's a one-byte length.

Either way, what follows is a public-key packet with tag 6 (public key) and length 51. The original is in the old format, the output from GnuPG is in the new format, but the only difference between the two formats is the first byte. (That's partly due to the length encoding: depending on the length value and on the choice of old-format encoding, the encoding of the length could change between the two formats.)

The other packets already have a new-format tag.

I don't know why different software is using different formats. But the difference is only in the encoding. Both encodings represent the same data. Presumably GnuPG doesn't keep track of the input format, only of the input data, and always outputs new-format packets (except when the backward compatibility option --rfc1991 is in effect).

• Thanks! When I try to use the --rfc1991 like so, gpg --export --armor alex@flowcrypt.com --rfc1991, I get the error gpg: Note: '--rfc1991' is not considered an option. Am I using the option incorrectly? Jul 1 '20 at 18:38
• I looked into it a bit more and it turns out that as of version 2.1.0-beta783 (2014), the --rfc1991 option is no longer supported in gpg Jul 1 '20 at 20:16