Wie generiert GPG bei einem öffentlichen Schlüssel einen MD5-Fingerabdruck?

Wie generiert GPG bei einem öffentlichen Schlüssel einen MD5-Fingerabdruck?

Ich habe den folgenden öffentlichen GPG-Schlüssel in einer Datei mit dem Namen „ publickey.pubASCII Armor (Radix-64)“ gespeichert und codiert:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: 2.6.3ia

mQCNAzNko/QAAAEEANZ2kpN/oMkz4tqzxvKPZws/XwsD0Y+E5/y7P2DIw4uHS/4N
syQbgkdrZhPBlXDv68DQioHXWsb904qyr7iZB1LC5ItK9MgqlK+Z2mvPqsGbHM8J
+oYib8kf2zJ6HvrYrP7NYB0tN9YYum2ICtx+hIi6aKGXdB1ATA5erwYmu0N9AAUR
tClSYWxmIFMuIEVuZ2Vsc2NoYWxsIDxyc2VAZW5nZWxzY2hhbGwuY29tPokAlQMF
EDNko/QOXq8GJrtDfQEBKVoD/2K/+4pcwhxok+FkuLwC5Pnuh/1oeOYHiKYwx0Z3
p09RLvDtNldr6VD+aL9JltxdPTARzZ8M50UqoF9jMr25GifheFYhilww41OVZA3e
cLXlLgda1+t0vWs3Eg/i2b0arQQDaIq7PeRdjdEDgwnG4xBaqaAqfgxwOXJ+LPWF
hiXZ
=K7lL
-----END PGP PUBLIC KEY BLOCK-----

Wenn ich eingebe:

$ gpg --with-fingerprint publickey.pub

Ich erhalte den Fingerabdruck des Schlüssels:

Schlüsselfingerabdruck = 00 C9 21 8E D1 AB 70 37 DD 67 A2 3A 0A 6F 8D A5

Wie macht GPG das nun? Ich meine, gibt es einen Befehl, den ich ausführen kann, ohne ihn zu verwenden gpgund trotzdem denselben Fingerabdruck zu erhalten? Mit SSH kann ich beispielsweise mit einem öffentlichen Schlüssel Folgendes tun:

$ cat ~/.ssh/id_rsa.pub | awk '{print $2}' | base64 -D | md5

Und das gibt den gleichen Hash zurück wie:

$ ssh-keygen -l -f ~/.ssh/id_rsa.pub

Ich weiß, dass der tatsächliche Inhalt des öffentlichen Schlüssels sein sollte:

mQCNAzNko/QAAAEEANZ2kpN/oMkz4tqzxvKPZws/XwsD0Y+E5/y7P2DIw4uHS/4N
syQbgkdrZhPBlXDv68DQioHXWsb904qyr7iZB1LC5ItK9MgqlK+Z2mvPqsGbHM8J
+oYib8kf2zJ6HvrYrP7NYB0tN9YYum2ICtx+hIi6aKGXdB1ATA5erwYmu0N9AAUR
tClSYWxmIFMuIEVuZ2Vsc2NoYWxsIDxyc2VAZW5nZWxzY2hhbGwuY29tPokAlQMF
EDNko/QOXq8GJrtDfQEBKVoD/2K/+4pcwhxok+FkuLwC5Pnuh/1oeOYHiKYwx0Z3
p09RLvDtNldr6VD+aL9JltxdPTARzZ8M50UqoF9jMr25GifheFYhilww41OVZA3e
cLXlLgda1+t0vWs3Eg/i2b0arQQDaIq7PeRdjdEDgwnG4xBaqaAqfgxwOXJ+LPWF
hiXZ

Ohne den letzten =K7lLTeil, der sich auf die in Base64 kodierte CRC-Prüfsumme bezieht. Aber wenn ich eingebe:

$ echo -n "mQCNAzNko/QAAAEEANZ2kpN/oMkz4tqzxvKPZws/XwsD0Y+E5/y7P2DIw4uHS/4N
>     syQbgkdrZhPBlXDv68DQioHXWsb904qyr7iZB1LC5ItK9MgqlK+Z2mvPqsGbHM8J
>     +oYib8kf2zJ6HvrYrP7NYB0tN9YYum2ICtx+hIi6aKGXdB1ATA5erwYmu0N9AAUR
>     tClSYWxmIFMuIEVuZ2Vsc2NoYWxsIDxyc2VAZW5nZWxzY2hhbGwuY29tPokAlQMF
>     EDNko/QOXq8GJrtDfQEBKVoD/2K/+4pcwhxok+FkuLwC5Pnuh/1oeOYHiKYwx0Z3
>     p09RLvDtNldr6VD+aL9JltxdPTARzZ8M50UqoF9jMr25GifheFYhilww41OVZA3e
>     cLXlLgda1+t0vWs3Eg/i2b0arQQDaIq7PeRdjdEDgwnG4xBaqaAqfgxwOXJ+LPWF
>     hiXZ" | base64 -D | md5

Ich erhalte die folgende Ausgabe:

4697e84969da935454c7f2cdc19aaf08

Was, wie Sie sehen, nicht passt00 C9 21 8E...

Überprüfung des RFC 4880 ->https://www.rfc-editor.org/rfc/rfc4880#section-12.2:

Bei einem V3-Schlüssel besteht die acht Oktette lange Schlüssel-ID aus den unteren 64 Bits des
öffentlichen Moduls des RSA-Schlüssels.

Der Fingerabdruck eines V3-Schlüssels wird durch Hashen des Hauptteils (aber nicht der Länge von zwei Oktetten) der MPIs gebildet, die das Schlüsselmaterial bilden (öffentlicher
Modul n, gefolgt vom Exponenten e) mit MD5. Beachten Sie, dass sowohl V3-Schlüssel
als auch MD5 veraltet sind.

Ein V4-Fingerabdruck ist der 160-Bit-SHA-1-Hash des Oktetts 0x99,
gefolgt von der Paketlänge von zwei Oktetten, gefolgt vom gesamten
Public-Key-Paket, beginnend mit dem Versionsfeld. Die Schlüssel-ID sind die niederwertigsten 64 Bits des Fingerabdrucks.

Wie wird es in einen Befehlszeilenbefehl übersetzt?

EDIT 1: Ich versuche, das mit zu tun pgpdump -i:

$ pgpdump -i publickey.pub
Old: Public Key Packet(tag 6)(141 bytes)
    Ver 3 - old
    Public key creation time - Mon Apr 28 17:19:48 MSD 1997
    Valid days - 0[0 is forever]
    Pub alg - RSA Encrypt or Sign(pub 1)
    RSA n(1024 bits) - d6 76 92 93 7f a0 c9 33 e2 da b3 c6 f2 8f 67 0b 3f 5f 0b 03 d1 8f 84 e7 fc bb 3f 60 c8 c3 8b 87 4b fe 0d b3 24 1b 82 47 6b 66 13 c1 95 70 ef eb c0 d0 8a 81 d7 5a c6 fd d3 8a b2 af b8 99 07 52 c2 e4 8b 4a f4 c8 2a 94 af 99 da 6b cf aa c1 9b 1c cf 09 fa 86 22 6f c9 1f db 32 7a 1e fa d8 ac fe cd 60 1d 2d 37 d6 18 ba 6d 88 0a dc 7e 84 88 ba 68 a1 97 74 1d 40 4c 0e 5e af 06 26 bb 43 7d 
    RSA e(5 bits) - 11 
Old: User ID Packet(tag 13)(41 bytes)
    User ID - Ralf S. Engelschall <[email protected]>
Old: Signature Packet(tag 2)(149 bytes)
    Ver 3 - old
    Hash material(5 bytes):
        Sig type - Generic certification of a User ID and Public Key packet(0x10).
        Creation time - Mon Apr 28 17:19:48 MSD 1997
    Key ID - 0x0E5EAF0626BB437D
    Pub alg - RSA Encrypt or Sign(pub 1)
    Hash alg - MD5(hash 1)
    Hash left 2 bytes - 29 5a 
    RSA m^d mod n(1023 bits) - 62 bf fb 8a 5c c2 1c 68 93 e1 64 b8 bc 02 e4 f9 ee 87 fd 68 78 e6 07 88 a6 30 c7 46 77 a7 4f 51 2e f0 ed 36 57 6b e9 50 fe 68 bf 49 96 dc 5d 3d 30 11 cd 9f 0c e7 45 2a a0 5f 63 32 bd b9 1a 27 e1 78 56 21 8a 5c 30 e3 53 95 64 0d de 70 b5 e5 2e 07 5a d7 eb 74 bd 6b 37 12 0f e2 d9 bd 1a ad 04 03 68 8a bb 3d e4 5d 8d d1 03 83 09 c6 e3 10 5a a9 a0 2a 7e 0c 70 39 72 7e 2c f5 85 86 25 d9 
        -> PKCS-1

Wie soll ich Modul und Exponent extrahieren? Ich denke, ich sollte etwas mit diesem Teil der Ausgabe machen:

Hash left 2 bytes - 29 5a 
RSA m^d mod n(1023 bits) - 62 bf fb 8a 5c c2 1c 68 93 e1 64 b8 bc 02 e4 f9 ee 87 fd 68 78 e6 07 88 a6 30 c7 46 77 a7 4f 51 2e f0 ed 36 57 6b e9 50 fe 68 bf 49 96 dc 5d 3d 30 11 cd 9f 0c e7 45 2a a0 5f 63 32 bd b9 1a 27 e1 78 56 21 8a 5c 30 e3 53 95 64 0d de 70 b5 e5 2e 07 5a d7 eb 74 bd 6b 37 12 0f e2 d9 bd 1a ad 04 03 68 8a bb 3d e4 5d 8d d1 03 83 09 c6 e3 10 5a a9 a0 2a 7e 0c 70 39 72 7e 2c f5 85 86 25 d9  

Ich habe versucht, die Binärwerte dieser Hex-Ziffern wiederzugeben:

29 5a(Hash übrig 2 Bytes) verknüpft mit: 62 bf fb 8a 5c c2 1c 68 93 e1 64 b8 bc 02 e4 f9 ee 87 fd 68 78 e6 07 88 a6 30 c7 46 77 a7 4f 51 2e f0 ed 36 57 6b e9 50 fe 68 bf 49 96 dc 5d 3d 30 11 cd 9f 0c e7 45 2a a0 5f 63 32 bd b9 1a 27 e1 78 56 21 8a 5c 30 e3 53 95 64 0d de 70 b5 e5 2e 07 5a d7 eb 74 bd 6b 37 12 0f e2 d9 bd 1a ad 04 03 68 8a bb 3d e4 5d 8d d1 03 83 09 c6 e3 10 5a a9 a0 2a 7e 0c 70 39 72 7e 2c f5 85 86 25 d9

Und der Befehl, den ich schließlich erhielt, war:

$ echo -ne "\x29\x5a\x62\xbf\xfb\x8a\x5c\xc2\x1c\x68\x93\xe1\x64\xb8\xbc\x02\xe4\xf9\xee\x87\xfd\x68\x78\xe6\x07\x88\xa6\x30\xc7\x46\x77\xa7\x4f\x51\x2e\xf0\xed\x36\x57\x6b\xe9\x50\xfe\x68\xbf\x49\x96\xdc\x5d\x3d\x30\x11\xcd\x9f\x0c\xe7\x45\x2a\xa0\x5f\x63\x32\xbd\xb9\x1a\x27\xe1\x78\x56\x21\x8a\x5c\x30\xe3\x53\x95\x64\x0d\xde\x70\xb5\xe5\x2e\x07\x5a\xd7\xeb\x74\xbd\x6b\x37\x12\x0f\xe2\xd9\xbd\x1a\xad\x04\x03\x68\x8a\xbb\x3d\xe4\x5d\x8d\xd1\x03\x83\x09\xc6\xe3\x10\x5a\xa9\xa0\x2a\x7e\x0c\x70\x39\x72\x7e\x2c\xf5\x85\x86\x25\xd9" | md5

Das sollte die Binärdaten dieser Hexadezimalziffern ausgeben und dann den MD5-Hash für diese Binärdaten berechnen, aber der Hash, den ich erhalte, ist immer noch anders:

6f09f2ac5c5af1c6dd3833e584387103

Ich weiß, dass ich es falsch mache, aber ich habe keine Informationen dazu gefunden, wie ich die Ausgabe richtig interpretiere pgpdumpund welche Teile ich verketten und dann hashen soll …

BEARBEITEN:Dank Jens Erat kann ich aus dieser kleinen „Auseinandersetzung mit den Fingerabdrücken von OpenPGP“ folgendes schließen:

FürV3-Schlüssel RSA 1024 BitSchlüssel gehasht mitMD5wird der Fingerabdruck berechnet gegen129Bytes bestehend aus den128Bytes desRSA und MPI(beginnend beim Byte-Offset14(vorausgesetzt, das erste Byte liegt am Offset1) des unverarbeiteten öffentlichen OpenPGP-Schlüssels, exportiert mit gpg --export $UID) verknüpft mit1Byte, das ist das Byte am Offset144und daher das Weglassen der2Länge Bytes bei Offset142Und143, wie RFC 4880 sagt.

Der folgende Befehl berechnet den Fingerabdruck unter Verwendung der GPG-Rohdaten und:

gpg --export $UID | xxd -p | tr -d '\n ' | tail \
-c +27 | cut -c -256,261-262 | sed -e 's/[0-9a-fA-F]\{2\}/\\\\x&/g' | while read TMP; do \
echo -ne $TMP; done | md5 | sed -e 's/[0-9a-f]\{2\}/ &/g' | \
awk '{print "\n MD5 fingerprint:"toupper($0)"\n"}' 

Wobei $UID die UID des Schlüsselinhabers ist.

Bei öffentlichen OpenPGP V4 RSA-Schlüsseln sieht die Sache anders aus:

Bei 2048-Bit-RSA-öffentlichen Schlüsseln wird der Fingerabdruck durch Hashen der ersten 272 Bytes der Rohdaten des OpenPGP-Schlüssels mit SHA1 ermittelt:

gpg --export $UID | head -c 272 | shasum | grep -Eo "[0-9a-f]+" | sed -e 's/[0-9a-f]\{4\}/ &/g' | \
awk '{print "\n RSA 2048 bit SHA1 fingerprint:"toupper($0)"\n"}'

Bei 4096-Bit-RSA-öffentlichen Schlüsseln wird der Fingerabdruck durch Hashen der ersten 528 Bytes der Rohdaten des OpenPGP-Schlüssels mit SHA1 ermittelt:

gpg --export $UID | head -c 528 | shasum | \
grep -Eo "[0-9a-f]+" | sed -e 's/[0-9a-f]\{4\}/ &/g' | \
awk '{print "\n RSA 4096 SHA1 fingerprint:"toupper($0)"\n"}'

Sollte reichen. Die Verwendung gpgsplitmit V4-Schlüsseln scheint jedenfalls portabler zu sein.

Antwort1

Bei OpenPGP-Schlüsseln ist es nicht so einfach wie bei SSH. Der Fingerabdruck wird nicht aus dem gesamten Base64-kodierten öffentlichen Schlüssel berechnet, sondern nur aus einigen (binären) Teilen davon.

Für einen OpenPGP-Schlüssel der Version 3 müssten Sie Folgendes tun:

  1. Analysieren Sie das öffentliche OpenPGP-Schlüsselpaket
  2. Extrahieren Sie für RSA Modul und Exponent
  3. Verketten Sie ihre Binärwerte
  4. Berechnen Sie die Hashsumme

Für Schritt 1 und 2 können Sie sich auf das Tool verlassen pgpdump, das die Zahlen anhand des -iFlags analysieren und ausgeben kann.

Bei Schlüsseln der Version 4 wird es sogar noch komplizierter.

Wenn Sie die Hashsumme zu Bildungszwecken berechnen möchten, empfehle ich pgpdumpstattdessen eine Erweiterung und die Verwendung des gesamten verfügbaren Parsercodes, damit Sie direkt mit den extrahierten Informationen arbeiten können. Ich bin mir ziemlich sicher, dass die Verarbeitung der binären Informationen auch einfacher sein wird als mit reinem Shellcode.

AKTUALISIEREN:Sie haben die falschen Ganzzahlen verwendet. Verwenden Sie stattdessen die in den Zeilen RSA nund RSA e. Alles in wenigen Zeilen mit Standardtools zusammenfassen:

pgpdump -i publickey.pub | \
grep -E '(RSA n|RSA e)' | \
cut -d'-' -f2 | \
tr -d "\n " | \
perl -e 'print pack "H*", <STDIN>' | \
md5sum

pgpdump -igibt die MPIs des Schlüssels aus, die wir grepauslesen, cutalles entfernen, was wir nicht brauchen, tralle Leerzeichen entfernen, mit ins Binärformat konvertieren perlund schließlich das berechnen md5sum.

Wird mit dem von Ihnen bereitgestellten Schlüssel ausgeführt:

$ pgpdump -i publickey.pub | \
> grep -E '(RSA n|RSA e)' | \
> cut -d'-' -f2 | \
> tr -d "\n " | \
> perl -e 'print pack "H*", <STDIN>' | \
> md5sum
00c9218ed1ab7037dd67a23a0a6f8da5  -

Scheint so ziemlich das zu sein, wonach wir suchen.

Der Vollständigkeit halber gilt das Gleiche für Schlüssel der Version 4, für die Sie eine andere Toolchain benötigen. Wir benötigen das vollständige öffentliche Schlüsselpaket. Um eine OpenPGP-Nachricht zu zerlegen, gpgsplitist dies praktisch. Anschließend können Sie sofort die sha1sumder Datei berechnen:

gpgsplit publickey.pub; sha1sum *.public_key

Beispielsweise läuft es mit meinem eigenen Schlüssel:

$ gpgsplit publickey.pub; sha1sum *.public_key
0d69e11f12bdba077b3726ab4e1f799aa4ff2279  000001-006.public_key

verwandte Informationen