HSG |
|
Kommt folgende Nachricht von Klaus Merkert? Wurde die Nachricht verändert?
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hallo liebe Lkler, dieser Text kommt von mk. Glaubt ihr das? Viele Gruesse mk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.2 (MingW32) iD8DBQFDTQXKWik4TmXUdgARAtsMAJ9EKdHKlBYDtxbmclYwrXlR0WGzPgCeKxE8 M+A1EVxzrLV2B4TFmViAB8Y= =eYfm -----END PGP SIGNATURE-----
Erzeuge eine Datei mmk.txt, die obige Nachricht enthält. Überprüfe die Signatur mit GnuPG. Welchen Schlüssel brauchst du dafür? mk-public-key.asc
gpg --verify mmk.txt
Verändere die Nachricht und kontrolliere erneut die Signatur.
Stephan Liell und Leon Schröder haben zur RSA-Signatur ein Comic dazu erstellt. Vorsicht, die Versionen sind je etwa 1,7 MB groß!
Die Vorgänge beim Signieren und bei der Überprüfung der Signatur sollen realistisch durchgeführt werden. In einem ersten Schritt lassen wir uns von krypto.py ein Krypto-System mit genügend großem n erzeugen.
>>> (e,d,n) = ks129() >>> e 4321 >>> d 105540278152442239156964372775953839871497419353759152866682265133093329419309672608340617518650663632935328045919317310113761185 >>> n 114381625757888867669235779976146612010218296721242362562561842935706935245733897830597123563958705058989075147599290026879543541
Jetzt wählen wir uns eine Original-Nachricht original, die unterschrieben werden soll.
>>> original = 'Überweise 100 €' >>> original 'Überweise 100 €'
Die Original-Nachricht ist ein String, der zunächst in eine Codierungs-abhängige Byte-Folge eoriginal (encoded original) verwandelt wird.
>>> eoriginal = bytes(original,'utf8') >>> eoriginal b'\xc3\x9cberweise 100 \xe2\x82\xac' >>> list(eoriginal) [195, 156, 98, 101, 114, 119, 101, 105, 115, 101, 32, 49, 48, 48, 32, 226, 130, 172]
Aus der Byte-Folge eoriginal wird nun ein Hash des gewählten Verfahrens erzeugt. sha1 besteht aus 20 Bytes. Mit Hilfe der Python-Bibliothek hashlib lassen wir uns den Hash errechnen.
>>> import hashlib >>> ho = hashlib.sha1(eoriginal) # ho = Hash Original >>> ho.digest() b'B#\xe7\x86\x8fG\xe4lx\xbda\x02M\xbc\xb9W\xa4[\xc3\xc9' >>> L = list(ho.digest()) >>> L [66, 35, 231, 134, 143, 71, 228, 108, 120, 189, 97, 2, 77, 188, 185, 87, 164, 91, 195, 201] >>> len(L) 20
Zur Verschlüsselung muss aus der Bytefolge eine Zahl zho (Zahl-Hash-Original) erzeugt werden.
>>> zho = bton(ho.digest()) >>> zho 377594085682662273889667993265979539981762020297
Diese Zahl zho wird nun - und das ist vielleicht überraschend - mit dem geheimen Schlüssel (d,n) zu zhoc (Zahl-Hash-Original-ciffriert) verschlüsselt.
>>> zhoc = modpower(zho,d,n) >>> zhoc 23356665507477810529268387333879606134859732585806800518553927498712741880026078527916394717542583907180086581967855821632025288
In der konkreten Anwendung müsste zur Versendung diese Zahl zhoc (Zahl-Hash-Original-ciffriert) in eine Bytefolge verwandelt werden. Diese Bytefolge wird dann zur Sicherheit oft base64-codiert. Der Empfänger muss dann daraus wieder die Zahl zhoc machen. Diese Schritte wollen wir uns der Klarheit wegen sparen.
Wie überprüft der Empfänger nun die Signatur?
Er erhält die unverfälschte - oder auch nicht - Bytefolge eempfangen. Die kann er mit dem Wissen um die Codierung in den String empfangen decodieren. Damit kann er das Original - oder seine Fälschung - lesen.
>>> # keine Fälschung >>> eempfangen = eoriginal >>> empfangen = str(eempfangen,'utf8') >>> empfangen 'Überweise 100 €'
Nun wird die Signatur überprüft. Dazu muss die Zahl zee (Zahl-encoded-empfangen), die sich aus dem Hash von eempfangen ergibt, mit der Zahl zhod (Zahl-Hash-Original-deciffriert), die sich aus der Entschlüsselung der Signatur ergibt, verglichen werden.
Ganz wichtig: Jeder kann die Signatur überprüfen, da jeder den öffentlichen Schlüssel (e,d) kennt bzw. dazu Zugang hat.
>>> he = hashlib.sha1(eempfangen) >>> he.digest() b'B#\xe7\x86\x8fG\xe4lx\xbda\x02M\xbc\xb9W\xa4[\xc3\xc9' >>> zee = bton(he.digest()) >>> zee 377594085682662273889667993265979539981762020297 >>> zhod = modpower(zhoc,e,n) >>> zhod 377594085682662273889667993265979539981762020297
Der Empfänger berechnet also einen eigenen Hash und vergleicht ihn mit dem deciffrierten Hash.
>>> zee == zhod True
Wer anderes als der Besitzer des geheimen Schlüssels kann dafür sorgen, dass dieses Verfahren aufgeht?
Verändere das Original zu
'Überweise 1000€'
Dabei wurde nur eine Leerstelle zu einer Null. (ord - Python-Dokumentation)
>>> bin(ord(' ')) '0b100000' >>> bin(ord('0')) '0b110000'
Die Nachricht bleibt also genauso lang und wurde nur um 1 Bit verändert.
Die empfangene Byte-Folge wird also jetzt
>>> eempfangen = bytes('Überweise 1000€','utf8') >>> eempfangen b'\xc3\x9cberweise 1000\xe2\x82\xac'
sein. Überprüfe damit die Signatur.
In der Konsole würde man einen Schlüssel direkt mit GnuPG so zertifizieren: 1. Mit gpg --list-keys Angaben der User-ID den betreffenden Schlüssel mit der Key-ID Key-ID ermitteln. 2. Mit gpg --sign (exportierbar) oder --lsign (nur lokal) Key-ID den Zertifizierungsablauf starten. Besitzt man mehrere Hauptsignierschlüssel, kann ein bestimmter Schlüssel mit gpg -u Key-ID in der Konsole oder über die Option default-key Key-ID in der gpg.conf festgelegt werden.