RSA Signierung

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

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

    Ja. Nimm noch SHA512.
    Ansonsten passt das. :thumbup:

    @EaranMaleasi Den privaten Schlüssel.

    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 :!:

    EaranMaleasi schrieb:

    Ich dachte schon den öffentlichen Schlüssel :whistling:

    Nein. Ich meinte den Private Key natürlich :thumbsup:
    Die Konstante RSA_KEY kommt dann weg und in den Konstruktor der RsaManager-Klasse kommt als Parameter eben dann rsaKey mit rein.
    Der wird dann eben aus einer Datei ausgelesen, die selbstverständlich verschlüsselt ist. Ansonsten hätte das Ganze ja gar keinen Sinn.
    Hab den Code in meinem letzten Post mal editiert.
    Noch Anmerkung zum Code-Design:
    Das ist ja eine Winz-Klasse! Die Methoden sind ja nur Einzeiler.
    Auch hat die Klasse gar keinen veränderlichen Status, also bei sowas würde ich eine statische Klasse nehmen - Objekte zu erstellen ist hier garnet erforderlich.
    Das Crypto-Dingens könnte man dann immer neu erstellen und gleich wieder disposen - ist doch dispoable, oder?

    Achtung: Dieser Post kann auch als OffTopic aufgefasst werden, und Einstieg sein in eine Diskussion über objektorientierte Programmierung (wann Klasse anlegen, wann statische Klasse)
    Also ignoriert ihn lieber, wenn ihr beim Thema bleiben wollt ;)
    @ErfinderDesRades Nein nein, das passt schon! Finde ich angebracht. Ich habe nie richtig objektorientiert programmiert und möchte mir das jetzt aneignen.
    der RSACryptoServiceProvider ist Disposable. Um die Klasse statisch zu machen, kann ich dann einfach die Methoden als Public Shared deklarieren?
    Stimmt, @Fortender. Du solltest noch IDisposable implementieren.
    Und nichts an Methoden statisch machen. Das mit den Instanzmembern stimmt schon so.

    Grüß
    #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 :!:

    Fortender schrieb:

    objektorientiert ... aneignen
    jo, dazu gehört natürlich auch, sich Gedanken zu machen, wann eine Klasse anlegen, und wann nicht.

    bei mir ohne Klasse sähe es evtl. so aus:

    VB.NET-Quellcode

    1. Imports System.Security.Cryptography
    2. Public Class RsaManager
    3. Const RSA_KEY_SIZE = 8192
    4. Private Sub New() 'Instanzierung verhindern
    5. End Sub
    6. Public Shared Function Sign(_data As Byte()) As Byte()
    7. Using _rsa = New RSACryptoServiceProvider(RSA_KEY_SIZE) With {.PersistKeyInCsp = False}
    8. Return _rsa.SignData(_data, GetType(SHA512))
    9. End Using
    10. End Function
    11. Public Shared Function Verify(_data As Byte(), _signature As Byte()) As Boolean
    12. Using _rsa = New RSACryptoServiceProvider(RSA_KEY_SIZE) With {.PersistKeyInCsp = False}
    13. Return _rsa.VerifyData(_data, GetType(SHA512), _signature)
    14. End Using
    15. End Function
    16. End Class
    So kannmans immer benutzen, und braucht nix dafür erstellen oder disposen.

    Alternativ käme ein Modul in Frage, in einem eigenen Namespace - so entspräche es den c#-static classes am ehesten.

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

    @ErfinderDesRades Es fehlt noch das Importieren des Private-Key's
    Außerdem dachte ich mir, dass es evtl. besser wäre zu instanzieren, da ich dann nicht dauernd einen RSACryptoServiceProvider anlegen muss und den Key reinladen.
    Das kostet nämlich zusätzlich Zeit, laut Trade sogar ein paar Sekunden. Wenn ich wie vorgesehen eine Datei in 1024byte Pakete unterteile und signiere/verifiziere, dann
    dauert das viel viel länger als mit meiner Klasse. Bin ich mir ziemlich sicher.

    VB.NET-Quellcode

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

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

    Wenn man den RsaCryptoServiceProvider global in der Klasse anlegt, was man normal macht, dann verwaltet die Klasse sehr wohl intern was. Dazu kommt ein Flag für's Disposen.
    Zudem braucht man zwei Konstruktoren, einen für das Angeben eines Keys und einen ohne, um Schlüssel zu generieren.

    Es fehlen auch entsprechende Properties.

    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 :!:
    Ja, wenn Gründe dafür vorliegen, macht mans natürlich als Klasse.
    Man kanns sogar auch ohne Gründe als Klasse machen, auch im Framework gibts glaub einige Klassen die eigentlich gar keine Statusse haben, und im INet finden sich glaub noch viel mehr Beispiele, wo professionelle Coder den Ansatz Klasse gewählt haben, auch wenn er eiglich verzichtbar gewesen wäre.

    Ich bin da vlt. kleinlich, ich lege Klassen nur an, wenn ich sie auch wirklich brauche.
    Also ich bin hier zufrieden, der Gedanke ist glaub verstanden.

    Man könnte noch den Singleton-Pattern anbringen, dann hätte man 3 Pattern nebeneinandergestellt, mit denen man den hiesigen Concern abhandeln könnte.

    Aber halt nur, wenn der RsaManager wirklich nicht mehr zu tun hat, als hier gezeigt ist. Kommen Gründe hinzu, die eine richtige Klasse erfordern, dann sind die anneren beiden Pattern halt draussen (Singleton ist hier imo eh weniger dolle als Static Class).
    Hab es jetzt mal erweitert und IDisposable implementiert.

    VB.NET-Quellcode

    1. Imports System.Security.Cryptography
    2. Public Class RsaManager : Implements IDisposable
    3. Const RSA_KEY_SIZE = 8192
    4. Private _rsa As RSACryptoServiceProvider
    5. Private disposed As Boolean = False
    6. Public Sub New(rsaKey As String)
    7. _rsa = New RSACryptoServiceProvider(RSA_KEY_SIZE) With {.PersistKeyInCsp = False}
    8. _rsa.FromXmlString(rsaKey)
    9. End Sub
    10. Public Sub New()
    11. _rsa = New RSACryptoServiceProvider(RSA_KEY_SIZE) With {.PersistKeyInCsp = False}
    12. End Sub
    13. Public ReadOnly Property PublicKey As String
    14. Get
    15. Return _rsa.ToXmlString(False)
    16. End Get
    17. End Property
    18. Public ReadOnly Property PrivateKey As String
    19. Get
    20. Return _rsa.ToXmlString(True)
    21. End Get
    22. End Property
    23. Public Function Sign(_data As Byte()) As Byte()
    24. Return _rsa.SignData(_data, GetType(SHA512))
    25. End Function
    26. Public Function Verify(_data As Byte(), _signature As Byte()) As Boolean
    27. Return _rsa.VerifyData(_data, GetType(SHA512), _signature)
    28. End Function
    29. Public Sub Dispose() Implements IDisposable.Dispose
    30. Dispose(True)
    31. GC.SuppressFinalize(Me)
    32. End Sub
    33. Protected Overridable Sub Dispose(disposing As Boolean)
    34. If disposed Then Return
    35. If disposing Then
    36. _rsa.Dispose()
    37. End If
    38. disposed = True
    39. End Sub
    40. End Class

    Wenn Du einen Key angibst, dann brauchst Du keine Size angeben. ;)
    Hier noch mein Lösung (C#):



    Sieht aber gut aus. Rufe noch im Konstruktor für die Generierung _rsa.ToXmlString(True) auf, dann wird das gleich generiert und nicht erst, wenn Du die Property aufrufst.

    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 :!:

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Trade“ ()

    Danke :)

    Hier nochmal das Update des Codes:

    VB.NET-Quellcode

    1. Imports System.Security.Cryptography
    2. Public Class RsaManager : Implements IDisposable
    3. Const RSA_KEY_SIZE = 8192
    4. Private _rsa As RSACryptoServiceProvider
    5. Private disposed As Boolean = False
    6. Public Sub New(rsaKey As String)
    7. _rsa = New RSACryptoServiceProvider() With {.PersistKeyInCsp = False}
    8. _rsa.FromXmlString(rsaKey)
    9. End Sub
    10. Public Sub New()
    11. _rsa = New RSACryptoServiceProvider(RSA_KEY_SIZE) With {.PersistKeyInCsp = False}
    12. _rsa.ToXmlString(True)
    13. End Sub
    14. Public ReadOnly Property PublicKey As String
    15. Get
    16. Return _rsa.ToXmlString(False)
    17. End Get
    18. End Property
    19. Public ReadOnly Property PrivateKey As String
    20. Get
    21. Return _rsa.ToXmlString(True)
    22. End Get
    23. End Property
    24. Public Function Sign(_data As Byte()) As Byte()
    25. Return _rsa.SignData(_data, GetType(SHA512))
    26. End Function
    27. Public Function Verify(_data As Byte(), _signature As Byte()) As Boolean
    28. Return _rsa.VerifyData(_data, GetType(SHA512), _signature)
    29. End Function
    30. Public Sub Dispose() Implements IDisposable.Dispose
    31. Dispose(True)
    32. GC.SuppressFinalize(Me)
    33. End Sub
    34. Protected Overridable Sub Dispose(disposing As Boolean)
    35. If disposed Then Return
    36. If disposing Then
    37. _rsa.Dispose()
    38. End If
    39. disposed = True
    40. End Sub
    41. End Class
    guck, derzeitiger Stand meiner Übungen:

    VB.NET-Quellcode

    1. Public Module RsaSignature
    2. Const RSA_KEY_SIZE = 512
    3. 'Const RSA_KEY_SIZE = 8192 'high security-level causes Durations of CspBlob-Creating about half a minute
    4. Public Sub CreateCspBlobs(ByRef privateCsp As Byte(), ByRef publicCsp As Byte())
    5. Using rsa = New RSACryptoServiceProvider(RSA_KEY_SIZE) With {.PersistKeyInCsp = False}
    6. privateCsp = rsa.ExportCspBlob(True)
    7. publicCsp = rsa.ExportCspBlob(False)
    8. End Using
    9. End Sub
    10. Public Function CreateSignature(data As Byte(), privateCspBlob As Byte()) As Byte()
    11. Using rsa = New RSACryptoServiceProvider(RSA_KEY_SIZE) With {.PersistKeyInCsp = False}
    12. rsa.ImportCspBlob(privateCspBlob)
    13. Return rsa.SignData(data, GetType(SHA1))
    14. End Using
    15. End Function
    16. Public Function VerifyData(data As Byte(), signature As Byte(), publicCspBlob As Byte()) As Boolean
    17. Using rsa = New RSACryptoServiceProvider(RSA_KEY_SIZE) With {.PersistKeyInCsp = False}
    18. rsa.ImportCspBlob(publicCspBlob)
    19. Return rsa.VerifyData(data, GetType(SHA1), signature)
    20. End Using
    21. End Function
    22. End Module
    Macht glaub auch alles, was gebraucht wird, und sogar recht simpel zu bedienen.
    Zu Verwenden ist das einerseits beim Sender, der generiert sich CryptoServiceProviderParameterBlobs (#7,#8). Das sind Byte-Arrays, mit denen man son RSA-Dingens quasi serialisieren kann, also abspeichern, verschicken, und woanders kann man 1:1 den CSP daraus wieder rekonstruieren (.ImportCspBlob(blob), #7, #14), inklusive Einstellungen und auch des Public/Private-Keys vom RSA.
    Und der Sender generiert sich beide Blobs, für Privat zum signieren, und für Public zum Verifizieren.
    Der Public CryptoServiceProviderParameterBlob muss dem Empfänger mitgeteilt sein, auf anderem Wege, als wie er letztlich die Nachrichten bekommt.
    Dann kann man-in-the-middle nur die Daten und ihre Signaturen verändern, aber damit fliegt er ja auf, denn er kann ja nicht den Public-CryptoServiceProviderParameterBlob im Empfänger verändern, mit dem verifiziert wird :P
    Jo, als TestCode habich solch verzapft:

    VB.NET-Quellcode

    1. Private Sub btTest_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btTest.Click
    2. 'data-sender-side
    3. Dim publicCsp As Byte() = Nothing 'publicCsp, to be shipped to Receivers
    4. Dim privateCsp As Byte() = Nothing 'stays at sender, to sign data
    5. RsaSignature.CreateCspBlobs(privateCsp, publicCsp)
    6. Dim data = New Byte() {1, 2, 3, 4, 5, 6}
    7. Dim signature = RsaSignature.CreateSignature(data, privateCsp)
    8. ''man in the middle-manipulation:
    9. 'data(4) = 9
    10. 'signature(20) = 8
    11. ''data-receiver-side
    12. Dim isValid = RsaSignature.VerifyData(data, signature, publicCsp)
    13. Call (If(isValid, System.Media.SystemSounds.Asterisk, System.Media.SystemSounds.Hand)).Play()
    14. End Sub

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