RSA Signierung

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 50 Antworten in diesem Thema. Der letzte Beitrag () ist von ThuCommix.

    RSA Signierung

    Guten Morgen,
    Ich bin im Moment dabei mich ein wenig in die Netzwerkprogrammierung noch tiefer einzuarbeiten und bin da über das Thema Sicherheit gestolpert.
    Zum Thema Datenübertragung (z.b. Updater, P2P-Filetransfer, usw...) ist mir dann aufgefallen, dass per ARP Spoofing (Man-In-The-Middle-Angriff) ziemlich
    leicht Pakete abgefangen bzw. noch schlimmer, verändert/ausgetauscht werden können. Um das zu vermeiden habe ich mich ein wenig eingelesen und hab mich jetzt
    auf RSA beschränkt, da diese asymmetrisch arbeitet und man so nicht auch noch den Geheimschlüssel zum Beispiel per Diffie-Hellman-Schlüsselaustausch sicher übertragen muss.
    Mir haperts aber ein wenig an dem Verständnis.
    Ablauf ist doch folgender (?):
    Datenpakete werden z.b. mittels 4096bit Public-Key und 512bit SHA HashAlgo signiert. Datenpakete, Public-Key und Signatur übertragen. Zur Verifzierung reicht aber (falls ich mich nicht verlesen habe)
    der Public Key, oder nicht?

    1. Was hat dann der Private-Key genau damit zutun und wie wird der genau berechnet bzw. wie kommt dieser zum Einsatz?
    2. Kann ein Angreifer, dann nicht die Updatepakete ersetzen und zusätzlich diese wiederrum signieren und zusammen mit dem Public-Key ersetzen?

    MfG Tim

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Fortender“ ()

    Moin,

    Datenpakete werden mit dem PrivateKey und einem Hash signiert. Idealerweise nimmt man als Schlüssellänge 4096Bit und für den Hash SHA512.
    Deshalb privater Schlüssel, denn nur Du darfst signieren.

    Der PublicKey darf nicht irgendwo auf dem Server liegen und übertragen werden, sondern muss in die Anwendung einkompiliert werden und darin liegen, sonst wäre er austauschbar und das System nutzlos.
    Und jo, mit diesem wird dann in der Anwendung verifiziert.

    Damit sollten sich Deine Fragen erledigt haben.
    Zum 2. noch: Wenn man das, wie gesagt, einkompiliert, dann kann eben der Angreifer keine Pakete austauschen, selbst wenn er diese signiert, da in der Endanwendung der PublicKey so bleibt und somit am Ende die Verifizierung failt.
    Würde man den so mitliefern, dann wäre es natürlich austauschbar. ;)

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    vlt. nutzt auch Verschlüsseln und Autentifizieren

    klärt vonne Theorie nur die Begriffe, und geht dann mehr auf die Praxis ein.
    Findich aber auch wichtig, aufzuzeigen, dass das Framework für den ganzen Kram bereits fixnfertiges Zeugs bereithält.
    Auch mit Diffie-Hellmann sollte man nix zu tun haben müssen, sondern einfach bei einer Tcp-Verbindung SSL-Übertragung aktivieren und fertig - bei anderen Übertragungs-Arten entsprechend.

    Leider habich das noch nie praktisch hinbekommen, aber solch sollte nicht dazu verleiten, anzufangen, selbst ein Diffie-System zu coden oder gar ein RSA.
    Sondern wenn mans braucht sich halt hinterklemmen, rauszukriegen, wie man das benutzt, wasses schon gibt.

    Nicht das Rad neu erfinden!

    Mein Prob war übrigens immer, das mit den Zertifikaten richtig zu backen. Wenn ich recht verstund und erinner, geht richtiges TLS nur, wenn man bei Installation des ausgelieferten Programms auch das zur Anwendung gehörende Zertifikat im Windows-Zertifikat-Store installiert (und da verlier ich die Lust, für meine Spielereien sonen Aufriss zu treiben)
    @ErfinderDesRades Will ja nichts sagen, aber was hat das mit asymmetrischen Kryptosystemen zu tun? Hier geht es ums Signieren und nicht um Verschlüsselungen oder Authentifikation.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Danke für die vielen Antworten. Ich glaub ich hab mich da im Halbschlaf falsch ausgedrückt. Ich meine natürlich "asymmetrisch und symmetrisch" (ich dummkopf).

    @ErfinderDesRades Ich meine zunächst die Signierung. Bei einem Updater ist es ja egal ob das Update abgefangen werden kann, es geht ja im Prinzip nur drum, dass
    das Paket so ankommt wie es verschickt wurde, um Mittelmännern den Paketaustausch zu erschweren.

    Reicht es deiner Meinung nach bei einer Tcp Verbindung einfach SSL anzuschalten? Würde mich auch mal interessieren, weil dann könnte man sich das in ein paar Bereichen sparen.

    @Trade
    Wie kompilierst du den Public Key ins Programm ein? Ich gehe mal nicht davon aus, dass du einfach ein ReadOnly Byte-Array irgendwo im Code hinterlässt. Machst du das per Resource?
    Und selbst wenn das einkompiliert wurde, könnte ein Angreifer dein Programm dekompilieren und den Public Key auslesen oder nicht?
    Wie macht das der RsaServiceProvider? Du lieferst ihm doch praktisch den Public-Key per Rsa XML String. Dieser muss doch dann einen Private-Key generieren und damit die Daten signieren.

    MfG Tim
    Na, einfach als XML-String im Programm abspeichern, z. B. als Konstante.
    Und wie soll der Angreifer denn in so einem Fall auf Deinem PC das Programm dekompilieren? Selbst wenn er das macht, das bringt ihm ja nichts, denn aus dem PublicKey kann er ja keinen privaten Schlüssel generieren. Das ist ja der Sinn des asymmetrischen Kryptosystems.

    Der RsaCryptoServiceProvider erstellt ein Schlüsselpaar. Den privaten Schlüssel lässt Du bei Dir lokal und den öffentlichen kompilierst Du in die Anwendung mit ein.
    Der PrivateKey kommt also nur beim Signieren zum Einsatz, danach wird der woanders nicht mehr gebraucht. Geht dann alles intern über das System.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Der Private-Key wird nur beim signieren gebraucht, das hab ich auch verstanden. Wenn ich aber ein Update bereitstellen will, muss ich doch
    immer mit dem selben Private-Key signieren, sonst würde die Validierung ja ansonsten fehlschlagen(?) Also muss ich diesen doch für den Programmteil, der
    die Updates bereitstellen soll, den Private-Key ebenso speichern(einkompilieren)

    MfG Tim
    hier gehts auch darum: activevb.de/tipps/vbnettipps/tipp0099.html
    Aber ich hab den Tipp nicht ausprobiert (oder doch, aber vor langem, und hab einiges dran geändert, aber leider meine Sources flöten)
    Also ich bin nicht ganz sicher, ob Danielo das auch richtig macht.

    zu Tcp: wie gesagt, vorgesehen ist das, und das reicht dann auch. Nur praktisch ists mir nie gelungen.
    Und wenn ich mich recht erinnere, muss dazu das richtige Zertifikat auf dem Rechner installiert sein.
    Ich glaub man konnte das sogar umschiffen, wenn man in einem Callback einfach immer True zurückgab, aber ich rede wirres Zeug, und mag dabei meine Übungen mit TcpClient und TcpChannel durcheinanderbringen.

    Leute mit Admin-Erfahrung finden Zertifikat installieren vlt. kinderleicht - mir war das damals einfach zu mühsam.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ja, den musst Du natürlich speichern. Die Schlüssel bleiben gleich, aber die Daten ändern sich jedes Mal.
    Einkompilieren ist halt so eine unflexible Sache, vor allem, wenn man mehrere Projekte hat, die mit Updates versorgt werden müssen.

    Von daher ist am Besten immer flexibles Speichern, am Besten auch noch verschlüsselt (AES 256).

    @ErfinderDesRades Das Beispiel ist sehr sicherheitskritisch. Die Schlüssel werden von .NET gespeichert und SHA1, naja..

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Nö, eben nicht. Das spielt ja genauso eine Rolle im effektiven Einsatz. Was ich zu Deinem obigen Beispiel zudem noch sagen möchte: 1024 Bit Schlüsselgröße, das ist nicht unbedingt sicher genug.
    Also bitte dieses Beispiel nicht unbedingt nutzen und wenn nur unter der Anpassung, dass es dann sicher genug ist.
    Und natürlich fliegt das wirklich auf, sobald Daten geändert werden. Habe ich ja in nUpdate auch verwendet und entsprechend getestet.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Ich habe mir zum testen einen rsa key generieren lassen und habe ihn per RSACryptoServiceProvider.ToXmlString ausgeben lassen und ihn anschließend als Konstante
    "einkompiliert".

    Meine RSA Klasse sieht jetzt so aus:

    VB.NET-Quellcode

    1. Imports System.Security.Cryptography
    2. Public Class RsaManager
    3. Const RSA_KEY_SIZE = 8192
    4. Private _rsa As RSACryptoServiceProvider
    5. Public Sub New(rsaKey As String)
    6. _rsa = New RSACryptoServiceProvider(RSA_KEY_SIZE) With {.PersistKeyInCsp = False}
    7. _rsa.FromXmlString(rsaKey)
    8. End Sub
    9. Public Function Sign(_data As Byte()) As Byte()
    10. Return _rsa.SignData(_data, GetType(SHA512))
    11. End Function
    12. Public Function Verify(_data As Byte(), _signature As Byte()) As Boolean
    13. Return _rsa.VerifyData(_data, GetType(SHA512), _signature)
    14. End Function
    15. End Class


    Ist das so sicher genug? Was ich noch machen werde ist, dass ich wie von Trade vorgeschlagen die Keys zur Laufzeit einlese und vorher mit AES256 verschlüssle.

    MfG Tim

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Fortender“ ()