7
$\begingroup$

I would like to know how to generate a fingerprint for an openPGP public key.

To be clear, I'm interested in how the fingerprint is generated. I'm aware that I can get the fingerprint with a commandline tool.

I've consulted the PGP docs here, but haven't been able to reproduce the known fingerprint of the key I'm interested in.

The key I'm trying to fingerprint is:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: Keybase OpenPGP v2.0.49
Comment: https://keybase.io/crypto

xsFNBFaVsC8BEADPvQH7xlfx2HJf7wQjPkFpkRCGSWR+lSo+cS3Ci81HcguLqt/l
WYbIbe83ixV9/1q9JifmGVs+iOKiGOF4gr1KisYhoO4b+rNiRphWQktjeZGGehzN
qtP8mFPOsxGonJI5iBo9EpQY3LhJm5Qh5NNHmDJURQTbefW4XCbecgYuy4R6t3zJ
tX4i+WKodD0qD41+9QgDO96BR6IHj3EM4HjqknNwNPU8aQEETrYfgw06bWR7Rtl/
iXstUCb0T4hQb8ygmmePwI5x5jPpZEKCVuYyoh6P2jbpuHlTsQUGoSislfLBp5gH
sb5C0Gk1ER+0VgYMiHu7uZaTHiU6HqhnFUxXZddLZowlfrJMR6LTbgCqkG1OipSc
H407N5MxH3QE1sx9Io/YXfh0F2emjjv+VeknwQCRE2Lc+NxsQk5V0ukpUml2om2K
fwVsW6HRLomRNupFdxwMCf9FfRglrog2ss9grvs1TzAMSj3XN9BrdoPupmf7B49z
I54iu19Tyg2ffb8EWbxQ4icOiTDg/KQWw4nGY5iVsZq6gyhzVtiQB8lw5ToavCgx
xltObGVpbnyMti/tMhY0rVUPW7T70mEIXL1gSsgBuHACtuGyHdyy4d0h5sOpnYDm
PwxkpHyFV1Kbtu6KS6WD0ThNa0zkKjfnWidiWjZagNqMmSaRkmYd5hm0UwARAQAB
zSVDaHJpcyBCbGFkZXMgPGNocmlzZGJsYWRlc0BnbWFpbC5jb20+wsF0BBMBCgAe
BQJWlbAvAhsDAwsJBwMVCggCHgECF4ADFgIBAhkBAAoJEDED5iuB2etS5MIP/iKL
m0IXGeu9s5qCwTbX1Doth7b0NznwqvI1zsnSfLDYII2kGq75A4xKr2ZrllKpXtpD
slMD68Lgz9swTYhfnN7H0VnurGF02du0zLzPSu/xz/K3ZYZyMAoWtWteTjuDsN3w
Q5ncB2Ij5ATA2x9ZryXBE9ABCO0uNaXC2Q+0UC8YYdbHHsUI3bUbM63+lleOzm67
uff4Py4oWNAgL1HAbeJBiJUthX4v0Ya70yJOd6uYHJryUXq2yesNjJfEoYgN/sB7
6R7eys5iz7yGkQAqt4BD7CCSdrAy/c0VO8vO6B/Jei6o8Mhp1h3URk9gaB60k8/8
E8g7mP2N6mnBS5YMJKdublzO0lz2w7Kt1fbJQbI5N/vl7YIT+sweachjqoRjgmQd
qyDo0i03OvNYotSuKNeJd3s/+XWUCw6NsRj2if0fhr/bXcaZF8zTXtr5sHSJfn/h
TgDqIhjBZb6/wTHUMPIibPHY7YSpIuOaSpJtsFuRlOUI8b08nQtEoRpXurZTgVUp
jeIw6QozCf3v0KEMLVoLKS6deIC9WGPp9Jsxj8KhDfU3NlH8wVbewVKQmuCcGoIR
uA0I8qchABcYUECcvTDQxh6ghXJOhluYGKOKzJLKW0OKkaCCe5WkK8dQPfkgF6z5
s0mCYwKNz54FReK64AOfDKBwgpJb2YNrHUXLYpuBzSlDaHJpcyBCbGFkZXMgPGNo
cmlzYmxhZGVzQHByb3Rvbm1haWwuY29tPsLBcQQTAQoAGwUCVpWwLwIbAwMLCQcD
FQoIAh4BAheAAxYCAQAKCRAxA+YrgdnrUlnuEACwcVkNwZJKcZzUK8n320J/kK2l
YJAFnZu9kpokEsYo1kky+YnwYSaeBMTwStUcBIbOz/V9BjBWLlDhJgPTtdN+/eDJ
0NO+m/mXmhIkOzwwmjO7tIcKz/M6KwDghASK9V/ZgNTccJkK48I5QOK9K2RkfR8T
g7+HwzXomr8JoScrbmUl65kGFaJhXw9gdxHxQdolGLA9AIIWgq77W/Mc9PlTEpDa
icL6cI9yYryroB7Yi2TIKWZibB21L4H9ljEtFag8rDK+RsCyOEe3G6E/OYNMPzHo
DJ6LjZKsBg3TCiTHuzpIRBRjPUw1foxCIgoTcaGzxK4RpjKuiy/twDcKNYL/gNuv
9ugYp+lHnMUZ1BlEEwArrVT+hfWLJzv1tWQ4RAcNe1eILi54SdI+NO9b5WUtIzsI
O8ZZygq3VKOQhBT0Hnx2J6Ayvc6Pu4a0ls+F82tuGH0j1v+g81/EpStYPJ8qhlfN
5wOqlyN/0nuVkZp5U/00x5zHnZBBSwzH6lIl0n7E2UPNtBXDKmt1cJahxrx4wdRT
OPoAciIzWKZLjp8yaeVMTk0ZAhxFAWUps6aALSGfMCmVZgyb2G///aIo++/mGzVa
gqAVw2XzDWYlL7tKnPvmyUXRBxNjVGfxfB+KYNnmtKsxyudP3iq6XIG9y1xXYc76
x5zsUaVYf5sZODgwCc0oQ2hyaXMgQmxhZGVzIDxjYmxhZGVzQHRocmVhdGNvbm5l
Y3QuY29tPsLBcQQTAQoAGwUCVpWwLwIbAwMLCQcDFQoIAh4BAheAAxYCAQAKCRAx
A+YrgdnrUo5eD/43uGwp1Qs7UNH6TwvWggi4VJLpk9Q+FsjDfF/TGtdSLIVnNjL+
DFj7LwSdSuAbEc8l+E5V8zx/p0MxhWGseQViRR9/Rq9hk8Ozs27CbL7aaZ85Zahp
AH3ZZsfD1js7UWx0RYW5/rkknPTNYqiKMcFe9kRIjVXO6P2fvIbvBRVY1dAsMsFX
PmcR5iYT0HiHZprySjrD2PI28TUV9fyCPSYdJadbfr0iAJ77v0l6GlztEacKK2/5
r7S5sC+GH+3ZDMrj+E0V4th7V8nQc2k+Ph/TvKsLEUK0U86axozPeUrK1ICNfiy4
UhmjyabW0mIPlvsqfrAXeVvdwQkuEvO2BK7VQTNDE3esvDJt5YjvDQQKD8YF0x39
mqMB8qYgNT8QjOpKUfRx7ew2+asGRSggI1EYE1p2f7AGb9xqw6mWBjLrdEVamY9C
g/tQ2/7GnkiXZ8WHGvvDTF9idCBRgUg4ZnPCkcbxjN01LNzqLCNXdCjPxF3zStQN
Ei/f9Kqcl8kKMX9Q2XCDMk/Wq+aJ6yfGoijgkRf6z4FauHesWpn4y/jWhMwCiFdi
2+9rFV0RIl1MdG93x2D3o/Ueley+046k4NxRKN+os5Nk9hHm5XMee4AbFsPpGbNQ
1bN5O1clG/yJQWjygZw+O9MHIbC4WEsLsouD8F7WXHWgOlR1z81myMteS87ATQRW
lbAvAQgA4BlTpub0bbB/obAMjqRR6oh77+FNJxh6VgvHsZx3+vlSLqdR2ikLVUAT
u/LLnvIT3BfGvskgTgVDnVjoPm8eFBDcChjTZniudNut8Iy01IlyCHbwojCKVtha
WO0kq2UO+niDq+2GU5OWneECe3NBdKSW0e3z3K/woO9Y1lZNNcLmkeayH/ma5YwS
nPF64Pi8boAiX+lVz3Zl5gxSy9eyQ1t1qin1lXC90kYH+8z0UNyDcd7p0aVWpjYc
fhHwInq8oWdn+1WsOHZbuy2v5vFHs4H40psErTGBYDAbny43Dysiu/w0Uwn9mO3W
117UdVraGM+YjnQBALKBgNDOpEvUhwARAQABwsKEBBgBCgAPBQJWlbAvBQkPCZwA
AhsMASkJEDED5iuB2etSwF0gBBkBCgAGBQJWlbAvAAoJEK8rFZL/rJGA0PUH/iH7
cQwQeMhZNU6yFqN3irvtmUbkPLpEOlLpQr7XuRsiiehM5aHZDoOu7MVw12MYwVdo
fRisHCbQbrCwHw07mPlfAYmGZblEkDPt4Dzz1d+t7QfNuNu4O0Uv3J2TNaaJ7PSe
1yoNKFseJIiBjW4V0/xhNBIbpaqQW1KfDJJUs2s4WJg12TnhmzGDkdw80l6MuvjQ
q1OUaC4ExY/XxKrry7e3o6uZqDWBqWK2sKXtKGr/eIRiYHRSkkrai3NGgsVmelNh
eoHG2ISDwvJdGqYSTh0Er+f/UZBLo2ubx1bkVwZ4/6nxysUoOMCzhQPf7kBcvpKO
JJba5SZs26QQbBM45qWRFhAAg3KaNA4jFTkdo13uopqtlWtJtXOFPXi8dQPAAKRk
025/YPWw8ivSsiOVcNsP6cOdmwlPKlj4OqiFh+Yq5zqnGE9GX+hpLLqv8m1UlySK
p7bHEwzno+eVCrVpMfQXKyM8zwvZ2HR9hQMaT9DYkPUws57mSWHQtdWO3Z3F0ogD
gAchAQPIw7IjM7zNuGPJelbogWssJlweoz2RxZR/7ehcyHugSGxV9Qub1gdZkBJS
aecwwszlsj0fK0skW0uBIDOpJlzosa5F1il5G+gpPE8p2bl2P1otBcPvvWT13zq1
CKGSoNWzeZaqe6hU8WnNYdXAakQViMPXkHmhn0vgAPhAcLSRK2xx18RtCqyGAk58
hR9T+woZYhFehjD1Fw7wIObl0pY+qMuLjzR48+6iJk7QE5c39ZIXag29D/BCtxoO
idTrEnZZOkZY0t5PdJUHyC3w659dsr6xC55mVBS5JTIQfOKbl9qYFvp+ywcwYvE4
gRFHZuzzufhWSm991P3lgw5oEMsnIsRPyZ2ZdNdeFF3UAEONmiv/kxFOcAq/cAxF
ElJ2x4HRxoIDIJCYMuzYxZ4ev2Z0sx0xCKeNRU4MODUl4/DRd3cOGv9X/5RKmGNO
rKooh+Q9/NP0riPUj698ADBmEoIGLaHhUzMHqbNT/Al1qVWNCps8rqpomOQktxiW
lIPOwE0EVpWwLwEIAN+6FoYKhWSj6YhFNh9u0D3cb1K0LcnzviosBzI5oIwA5Ewh
3mCSmxcKyTrML34XnrWBw+va4ARTTXt9hceeu8h77q1U4sksHqsjvkSneutucGIl
ASA3kxecHbd7x83Jz14nwSriCoLdhrSz9pEBBXLncBvAzbluCFKGYT8oKObb3yi9
N/Vm9BTXBD2OMl999Nn8o+BTtrweIPFiX0b9MOqDv7lmnjy4pBINg0DtqFM7yplw
xA/E3ysykH31fS7XUHC+s3+5AXbWLP9zJMETioxwQbMFpusFGa30PtZ7Fme6V7DK
36Lfioi1gAkWnVh4TheO/Wt4hv558UxVavT8AlMAEQEAAcLChAQYAQoADwUCVpWw
LwUJDwmcAAIbIgEpCRAxA+YrgdnrUsBdIAQZAQoABgUCVpWwLwAKCRBY38iIOY0Y
cs6XCADBueQ1RB+YgqT8punbPZbHIKCMoCPrjtlmDJkzTlsQXnvCkKcQFQeWgZ14
A7AQp1ByiDW+JPzEyHMxkJtIyarFCcikZ/vgEbhCw+AoZFgqBKWLF0DySCENOcv8
wFVxRMQCeLLnYUaAZMK9LXw76BHa0DTt9JyHvQnKhCZzKZ+UGHdcWS6tCshzcn+3
EZVVB7wT2TEpjH+10k8Q4jWHgXxKvYyRc5kQvL/GvFKBaVqScedydGLnUL9vX4P4
uejD0V5wiYjxHvlATvKR57EHmsKz6SpReMuJAJN2H5ClhaPiYmxEla6/whtxQz/z
0tG9pATZYFefpYNUitrMaQ833CJ/4HoP/RSP+sAs9cOUSbb0sEQMQ9Y64bXbDUXI
ZSaY0zOKbKtP3a71nrltMeQea9jUGZWhsaxxVVdOdMCIT7uBDFrF4TV1AtglggHl
HZEM/b3n+/I+xREhjBbN6eqebsYTmDfcdPVjYJG2qYnUuzNnXktKHSSeHVPYYGwp
D+EDQ7nZjfJNoz106kzT9f+u+/6p1TjQqdU17WoHrNIzUUW6adNa3ODZwdNGehBN
ujbuAq8KbdyLm+PvSAmHiThbgCymV8OtAf5FIorMhyyxI4PAg3aOeEKrPYE5F2JP
/a2qqxxTbgl1o2Scg9TNpeDa3AxsQ8m+XsS75rgig0UR9zL+ON5pqlTkB6jL1Hq+
+cyB/swJVhqdJHbIbToUa3SMwb1Sh5Qu85s7uqqDxiVCB7lOQVVYGoxfdcbF8j5E
8Ok/Jx6FwDcXzsLpUSAS2zPjSg3Cuup0iZ9iJD8T1cWWxU67mEDl0ktDreTspWA6
nam05PPsaLJ8LkZCME9cz0IyTHJ2Tz/Anen9ainSND5V09sb0ubBNjaCNVXQ+137
arH4iwvpVLT1zlag2/1A0dAAMz+xcft/xCyEfhlPqF0G312HKnwyv4hVBYQ8Blq4
szEq74aSGTnJxjFXpZEk7hCy1MdwUuXVeIn3Hmg9+84f860JAvc3sar5xTvjCm13
6RZ7aOZsD4ZW
=/HI0
-----END PGP PUBLIC KEY BLOCK-----

and on keybase.io the fingerprint is given as

07DBC7442CABB41ADCB031E03103E62B81D9EB52

Again: I'm interested in how the fingerprint is generated (not how to use the PGP software).

$\endgroup$
  • 3
    $\begingroup$ 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. This is from the OpenPGP standard, RFC 4880. $\endgroup$ – Maarten - reinstate Monica Jan 21 '16 at 22:50
  • 2
    $\begingroup$ @MaartenBodewes Reads like a valid answer to me… ;) $\endgroup$ – e-sushi Jan 21 '16 at 22:55
  • 2
    $\begingroup$ @e-sushi Just checking if I can calculate it as well, otherwise it's not fun. $\endgroup$ – Maarten - reinstate Monica Jan 21 '16 at 23:00
  • 1
    $\begingroup$ I put together the command line to calculate the fingerprint in an answer on Super User some time ago. It only discusses version 3 keys in detail though, and does not really take apart version 4 keys. $\endgroup$ – Jens Erat Jan 21 '16 at 23:26
6
$\begingroup$

Your fingerprint is for OpenPGP V4 compatible as it uses SHA-1. The fingerprint is 20 bytes instead of 16 for MD5 used in the older package format.

For V4 it is required to extract the public key packet first. This is likely to be the most tricky part, as PGP uses it's own packet format. You'll have to parse the binary data within your base 64 encoded blob to find the packet.

This is from the RFC 4880: OpenPGP standard, section 12.2:

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.

The Bouncy Castle for Java sources simply state the following in JcaKeyFingerprintCalculator:

byte[]             kBytes = publicPk.getEncodedContents();

MessageDigest   digest = MessageDigest.getInstance("SHA1");

digest.update((byte)0x99);
digest.update((byte)(kBytes.length >> 8));
digest.update((byte)kBytes.length);
digest.update(kBytes);

return digest.digest();

where publicPk and kBytes already contain the parsed packet.

So you have to use the pre-V4 encoded length, i.e. just a 16 bit big endian integer encoding.


In the above case the public key packet is at position [3, 528).


Fun brute force approach to find the location of the packet:

String base64Key = "xsFNBFaVsC8BEADPvQH7xlfx2HJf7wQjPkFpkRCGSWR+lSo+cS3Ci81HcguLqt/l"
        ....
        + "6RZ7aOZsD4ZW";
// note: don't include the checksum at the end, after and including the `=` sign.   

byte[] decodedKey = Base64.decode(base64Key);

System.out.println(decodedKey.length);

ByteBuffer encodedLength = ByteBuffer.allocate(2);

MessageDigest digest = MessageDigest.getInstance("SHA1");

int startOff = 0;
for (startOff = 0; startOff < decodedKey.length; startOff++) {
    for (int endOff = decodedKey.length; endOff > startOff; endOff--) {
        encodedLength.putShort(0, (short) (endOff - startOff));

        digest.update((byte) 0x99);
        digest.update(encodedLength.array());
        digest.update(decodedKey, startOff, endOff - startOff);
        byte[] fingerPrint = digest.digest();
        String hexFingerPrint = Hex.toHexString(fingerPrint);
        if (hexFingerPrint
                .equalsIgnoreCase("07DBC7442CABB41ADCB031E03103E62B81D9EB52")) {
            System.out.printf("%d - %d%n", startOff, endOff);
            return;
        }
    }
}
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.