PKI im Zusammenspiel mit .NET

  • PHP

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von nikeee13.

    PKI im Zusammenspiel mit .NET

    Hi,

    ich möchte eine Public-Key-Infrastruktur einrichten. Dabei soll ein PHP-Script, welches Zugriff auf den privaten Schlüssel hat, Daten mit diesem verschlüsseln. Der Public Key sollte zum Entschlüsseln dienen. Das Ganze ist also eine Signatur.
    Das Problem dabei ist allerdings, dass ich es nicht schaffe, einen mit PHP verschlüsselten String in C# mit dem Public Key zu entschlüsseln. Ich steige nicht ganz durch die Binärdatenverarbeitung in PHP durch, irgendwie klappt das nicht. Was das Ganze noch erschwert ist, dass PHP nicht die beste Programmiersprache im Umgang mit Character Encodings ist.
    Wenn ich auf beiden Seiten (Ver-/Entschlüsseln) die gleiche Programmiersprache verwende, funktioniert es jeweils. Das ist aber leider nicht der Zweck.

    Von daher frage ich mich:
    Wie erzeuge ich ein Schlüsselpaar, das in PHP und .NET/C# verwendbar ist, und wie stelle ich es PHP bereit und verwende es korrekt? Als Verfahren habe ich den DSA gewählt, falls Ihr da aber bessere/aktuellere Verfahren kennt, lasst es mich bitte wissen.
    Auf der PHP-Seite verwende ich openssl, in .NET/C# den System.Security.Cryptography-Namespace. Eigentlich ist DSA ja standardisiert und müsste sprachübergreifend problemlos funktionieren.

    Was am Ende dabei rauskommen soll, ist, dass ein Client eine Anfrage mit einem String sendet. Dieser String soll vom PHP-Skript signiert und zurückgegeben werden. Der Client kann die Signatur dann mit Hilfe des Public Keys validieren. Vielleicht fällt Euch dazu ja was angenehmeres ein.

    nikeee
    Von meinem iPhone gesendet
    Ja, natürlich. Habe vergessen, zu erwähnen, dass die zu signierenden Daten vorher noch durch eine Hashfunktion laufen (SHA512). Sonst wird der Output auch nicht immer gleich lang. ;)
    Ich denke aber, dass das Problem auch ohne das vorherige Hashen bestehen würde.

    Alleine, damit die Hashfunktion vom von Binärdaten in PHP das gleiche wie in C# liefert, musste ich die hexadezimalen Zahlen in ihre ASCII-Zeichen (und somit einer Art "Byte-Array", nur als String mit unlesbaren Zeichen) umrechnen. Das kann es doch aber wirklich nicht sein.

    Dieses Bild auf Wikipedia trifft mein Vorhaben ziemlich genau, nur ich mache das Ganze ohne Zertifikat/CAs. Also nur eine Hashfunktion und Ver/Entschlüsselung. Das sollte den Zweck erfüllen, denke ich.
    Von meinem iPhone gesendet

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

    AFAIK gibt PHPs hash()-Funktion den Hash als hexadezimal-kodierten String zurück (das Casing ist da egal). .NET gibt ein Byte-Array. (die - IMO - bessere Wahl, aber Byte-Arrays sind ja jetzt nicht so die Philosophie von PHP.)

    Aber nur um das Hashing geht es hier ja nicht. Primär mach ich mir um die Signatur Gedanken, weil das ja (noch) überhaupt nicht läuft.
    Von meinem iPhone gesendet
    Wäre es nicht möglich OpenSSL mit C# zu nutzen? Ich weiß grad nicht ob es einen Wrapper gibt, aber eine Win32-Lib wird sich doch wohl dafür finden^^

    edit: found sourceforge.net/projects/openssl-net/
    Eigentlich möchte ich eher bei dem .NET-Bordmitteln bleiben, vorallem weil .NET schon eine DSA-Implementierung hat.

    Edit:
    Ich habe das Problem nun 'gelöst'. Ich habe mir ein C#-Programm geschrieben, welches vom PHP-Skript aufgerufen wird (die Ausgabe wird abgefangen).
    Diese Lösung werde ich allerdings nicht Produktiv einsetzen. Ich habe mich dazu entschieden, die Webseite in ASP.NET (Razor) zu schreiben. Wurde eh mal Zeit, dass ich mich mit ASP.NET beschäftige.
    Von meinem iPhone gesendet

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

    Ich grabe diesen Thread noch einmal bewusst aus, um zu berichten, dass ich es jetzt einmal auf der Serverseite mit diversen nodejs-Modulen versuchen werde. Das ist mit Expressjs so oder so viel schöner als PHP. :P

    github.com/chrisa/node-rsa
    github.com/Obvious/ursa
    nodejs.org/api/crypto.html
    nodejs.org/api/crypto.html#cry…ignature_signature_format
    Als erstes werde ich es mit dem Crypto-Modul versuchen, da das mit node mitgeliefert wird.

    Ich werde meine Ergebnisse hier ebenfalls reinstellen (für die Nachwelt :)).

    Edit:

    Wunderbar - es funktioniert einwandfrei. Das Standard-Node-Module ist wirklich gut. Das einzig Bblöde ist, dass man in C# nicht einfach Dateien im PEM-Format in einen RSACryptoServiceProvider laden kann. Das ist aber nicht schlimm. Mit dem Workaround von dort:
    christian-etter.de/?p=771
    funktioniert es einwandfrei.

    Hier mein Testcode, für die Nachwelt:

    JavaScript-Quellcode

    1. // JavaScript - Node.js
    2. "use strict";
    3. var crypto = require("crypto");
    4. var s = crypto.createSign("RSA-SHA1");
    5. var value1 = "test Lol";
    6. var privateKeyPem = "-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKBgQDwIqfvxEjqHu8048x4wJ5EId6ASAbWdH5fzgHxvew5kXqECMNc\nXzRqDVnDVPQT41UeZs8HxouBE+ZA8DfnVlHwP4EIeigOUaqy0sseKpO71tupFU+2\nLjpcF6O7cVuLjt6476iYfSyrssK4hnmzVYGZNz16OSR9z/SuTd8BhohG4QIDAQAB\nAoGBAOmEmhEUrN9XU8D4IVfv4DhbQ1c2M8gKovYhjEx8J6LX8O9C4lAKmRrkfrzv\n+Sb59EVLLtrd3b2ZD1lpAMQrciMwC5PAa8da/J++lR1VjM5GbzqKjGtfx3WQlzNE\n1ZaZ2FSY8lAPMM4uLczyD79PJQBsGCcx3KDJRR5ENp6an5cRAkEA/m1FEqol/KKh\nxOyGsK4GVuansBXhrAgpwMlYLT+vF0gy1jzYQDNNQXzeQFYH6gZY66RTYFl3JPNL\n8KXLyhwDLQJBAPGew6xkLBoYi4IO9I+NP/gIHzSiQeEl2OxZsgZiz0Yh5E9ndwMr\n87jTX/4ZBwNlDC0E+MXsJpMSvTFNpw4rcwUCQQC5FU5JLKOjq79YnOPChWYxM2vL\nKa/YULvm9dGCYTCDFE9/EBYUZf2OZULctHjfYqyvBwRsM8j7hU26CzI7nbMlAkAA\nkVjwXMPlw80AHzzf4XsXAB3ip8bz2nzqAUPz0+OczJOWxC15am8GLij5leF4VpJy\nwKI9BNMKYW7kYMRVujBpAkEA7gQ8MGqjjrCAfOzrrC9ZuVdGRfEjUEdHMqiF+js7\nXNBvnT5lBznUOd+eta6CGo7S5hjU7D3CEzmVGQfxUsRZ1w==\n-----END RSA PRIVATE KEY-----";
    7. s.update(value1);
    8. var signedData = s.sign(privateKeyPem, "base64");
    9. console.log("Signature: ");
    10. console.log(signedData);


    Und am Client:

    C#-Quellcode

    1. // C#
    2. var publicKeyPem = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIqfvxEjqHu8048x4wJ5EId6A\nSAbWdH5fzgHxvew5kXqECMNcXzRqDVnDVPQT41UeZs8HxouBE+ZA8DfnVlHwP4EI\neigOUaqy0sseKpO71tupFU+2LjpcF6O7cVuLjt6476iYfSyrssK4hnmzVYGZNz16\nOSR9z/SuTd8BhohG4QIDAQAB\n-----END PUBLIC KEY-----";
    3. // Using extension methods from:
    4. // http://www.christian-etter.de/?p=771
    5. var signedString = "test Lol";
    6. var signedData = System.Text.Encoding.ASCII.GetBytes(signedString);
    7. var signature = Convert.FromBase64String("5MBXkvc19ItbBAl4X8K89wEJsazsXlDfUD6dBiV7+0EW5rewuRL0SVmXLPF+DHeUnBzbvL8DGBDy8OHtDCg6t4bDOvTiH8iJiVzS770qIauUkiVxSePUMmFnCzGcgLEGp2Z315ocBGPP5cj7kJ24/gTpgD19uc9DCo3vXQWCCzY=");
    8. bool isValidSignature;
    9. using (var rsa = new RSACryptoServiceProvider())
    10. {
    11. rsa.PersistKeyInCsp = false;
    12. rsa.LoadPublicKeyPEM(publicKeyPem);
    13. using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
    14. isValidSignature = rsa.VerifyData(signedData, sha1, signature);
    15. }

    Das Schlüsselpaar ist natürlich nur zu Testzwecken (nicht produktiv einsetzen, weil es jetzt öffentlich ist! :P).

    Um den Workaround zu vermeiden würde ich jetzt einfach die RSAParameter exportieren und dann darüber in das Programm einbauen - dann kann man den Workaround komplett weglassen und man braucht ihn nur zur Erstellung des XML-Strings.

    Wunderbar, damit kann ich arbeiten. Das wars.

    nikeee
    Von meinem iPhone gesendet

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „nikeee13“ ()

    nikeee13 schrieb:

    für die Nachwelt
    ...und genau deshalb grabe ich das hier noch mal aus.

    Gerade habe ich durch Zufall in meinem StackOverflow-Stream genau das gefunden, was ich anfangs vorhatte:
    RSA Sign with PHP, verify with C#

    Offenbar braucht man auf der PHP-Seite nur die phpseclib. Ob die gut ist, kann ich nicht sagen. Sie ist eine reine PHP-Implementierung der Algortihmen ohne OpenSSL oder ähnlichen Abhängigkeiten. Man müsste sich also darauf verlassen, dass die Entwickler davon wissen, was sie machen.
    Von meinem iPhone gesendet

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

    Ich habe mit den StackOverflow-Thread angesehen. Den php-Code habe Ich zum laufen gebracht, dieser gibt mir nun testweise ein verschlüsseltes "AAAAA-AAAAA-AAAAA-AAAAA" zurück.

    Allerdings verstehe Ich mit dem 2ten Teil (C#) nicht so richtig. :/



    C#-Quellcode

    1. bool success = false;
    2. using (var rsa = new RSACryptoServiceProvider())
    3. {
    4. StreamReader reader = new StreamReader(dataStream);
    5. String signedString = reader.ReadToEnd();
    6. byte[] signedBytes = Convert.FromBase64String(signedString);
    7. byte[] bytesToVerify = Encoding.UTF8.GetBytes(value);
    8. try
    9. {
    10. RSAParameters parameters = new RSAParameters();
    11. parameters.Exponent = new byte[] { 0x01, 0x10, 0x01 };
    12. parameters.Modulus = OtherClass.StringToByteArray(Program.Modulus);
    13. rsa.ImportParameters(parameters);
    14. success = rsa.VerifyData(bytesToVerify, new SHA1CryptoServiceProvider(), signedBytes);
    15. }
    16. catch (CryptographicException e)
    17. {
    18. Console.WriteLine(e.Message);
    19. }
    20. finally
    21. {
    22. rsa.PersistKeyInCsp = false;
    23. }
    24. }


    Was ist vorhabe ist wie folgt:
    1. vb.net sendet einen String an den Server (Problem gelöst)
    2. Der Server verschlüsselt nun das ganze (fügt ggf. noch Informationen hinzu) (Teil 1 vom StackOverflow-Thread)
    3. vb.net soll nun versuchen das ganze wieder mit dem PublicKey zu entschlüsseln. Wenn es Problemlos entschlüsseln werden kann weiß das Programm, dass der Server echt ist und kann die entschlüsselten Informationen verarbeiten
    Mein Problem ist nun, dass vb.net anscheinend nichts entschlüsseln kann, was von php verschlüsselt worden ist. Auch wenn es das gleiche Schlüsselpaar ist.


    mfg. Tim Strasser
    Ich sehe in Deinem Code nirgends was von Ver-/Entschlüsselung. Meinst Du (mal wieder) Signierung/Verifizierung, @timchen100?
    Schließlich rufst Du die VerifyData-Methode auf.

    Außerdem, wofür steht dein 'value'?
    #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 :!:
    Nein. Ich meine eigentlich nicht Signierung/Verifizierung.
    Mein Problem habe Ich oben schon erwähnt.

    Mein Problem ist nun, dass vb.net anscheinend nichts entschlüsseln kann, was von php verschlüsselt worden ist. Auch wenn es das gleiche Schlüsselpaar ist.

    Ich habe leider immer noch keine Lösung für das Problem gefunden.
    Poste mal bitte deinen PHP-Code.

    Edit: Am Besten ein kompilierbares .NET-Projekt und die PHP-Daten mit private und public Keys.
    Von meinem iPhone gesendet

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

    Hallo, erstmal entschuldige Ich mich, dass es so lange gedauert hat, aber Ich hatte leider früher keine Zeit.
    Ich habe das php und vb.net Projekt in einem ZIP-Ordner angehängt. Hier könnt ihr es runter laden.

    Bitte beachten: Die Private- und PublicKey's die in der php-Datei enthalten sind sind nur Testweise drin.

    Hier poste Ich den php-Code auch noch einmal einzeln:

    PHP-Quellcode

    1. <?php
    2. include('Crypt/RSA.php');
    3. $rsa = new Crypt_RSA();
    4. $rsa->loadKey('-----BEGIN PUBLIC KEY-----
    5. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtejsA/UO5dP0oTQ4w27K
    6. KRLq8RZ43b78zTLrm5C5xf6ixij3Vp43sBLsESrbQOZWCnMuUhtDkcH4RiJmM2ct
    7. 2wn2lTUKcHruF8H5vkMvUkwfafdv5udHAQB3/z5L4rHyDemDH9MQkzfpBzWAEHO0
    8. uUDqR/GaLLf1Kn5CbL+XE+tsPsrL4VT6GLY5SmHcXuWrKWjLkldXQfrpJDuoS3oG
    9. sKg9OXjY7vKO05wvwZKkv3L2cbOLPdUSxFhZ8L9urM2wxJZf4hdZO9TYO707bAct
    10. qT7iyqi6bZ06YL0MjYHVfwSXEg4vv0KypLbxqIi1WilND0B9QrgJoKi5Zt1pnHfU
    11. qQIDAQAB
    12. -----END PUBLIC KEY-----'); // public key
    13. $plaintext = 'Test';
    14. $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
    15. $ciphertext = $rsa->encrypt($plaintext);
    16. $rsa->loadKey('-----BEGIN RSA PRIVATE KEY-----
    17. MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC16OwD9Q7l0/Sh
    18. NDjDbsopEurxFnjdvvzNMuubkLnF/qLGKPdWnjewEuwRKttA5lYKcy5SG0ORwfhG
    19. ImYzZy3bCfaVNQpweu4Xwfm+Qy9STB9p92/m50cBAHf/PkvisfIN6YMf0xCTN+kH
    20. NYAQc7S5QOpH8Zost/UqfkJsv5cT62w+ysvhVPoYtjlKYdxe5aspaMuSV1dB+ukk
    21. O6hLegawqD05eNju8o7TnC/BkqS/cvZxs4s91RLEWFnwv26szbDEll/iF1k71Ng7
    22. vTtsBy2pPuLKqLptnTpgvQyNgdV/BJcSDi+/QrKktvGoiLVaKU0PQH1CuAmgqLlm
    23. 3Wmcd9SpAgMBAAECggEAJnwdmoS43ySlZ4ltzOLegCwRamnvrjIet6bjM6k9tEa3
    24. 1yaJlVipvWVzbfpcInHYmCNgFFzSQb8AsI3Mg2l7yRBli5GKINvRDVOra3Y5R7b1
    25. Gm0PzpD1c5/Ow0BBu7cb15ekdxInOo4kjbLi4hgojtzN8+SIUpeklZXapbku1Dap
    26. +IqYUWRV0i7ze+ArbOmkMv5xRyhu60G3+bTDoeJPl+ant36PHOZMnWbkvljLixkf
    27. kHVKPgs2ySgkfjHRCNQC3BBgJurFqmI5rihvzgpJ7SFIIpmpvmDz9Kj9zMF7zDkw
    28. Gb+trCbPJkna3iS8wzpYqTlOFNvD7OdUUQiBYe8/9QKBgQDRROnzkU3NpqqH2WrZ
    29. hDbTk5KuL9hG3aLv05hH0TMbLrP4DQzmVosfoZpqnKf50/IYCm/d8ygx0FW6mZln
    30. fGG+5W5mkb5UanHzUoPafsQb0CQydinWUz73LNfKA07fK5Xx5sax80ZcJSifjaAs
    31. oxeZ7ZDPf1JI+6ICYlseWGFEhwKBgQDeh/u/z7rScY0mD8J1LigJQnE0kGvJVKf5
    32. GqLyKcauKsg9v5KeNR3m9PAY+9MqUmO9O1LEcGgkLECOa+CsieVsc4ISsjUA9MPP
    33. LA+PE9AFzU1UeZyOUdIK5TjymLAZblDR+1U9Nrc9rmFEKj2UcLOlvB4kTC4Ia1v1
    34. QJMphkmZTwKBgEMPK00SzfTNqK3ZvQSw+oS4MHPC/zJOSa1Ch/TTk+XtBFzDidOx
    35. /ekH9xyc0LMc+OI9TfW4urOjyCUAnYjs8cGjccpKf8w7RAKt+XSl1J/5BfBpryRw
    36. DqhUZV3ly3t2UxluU1Oo2m4iti7SynYjWSfJWfM0IKEkiZjr/bjup1S3AoGAKqXF
    37. Ca22ED7S3kiG7A48fgnNyFUlUyB2ULdaIy7+dMKePbdJUii74ldu7FrWzXWcx9dm
    38. tV8VllkkxibGmEqVPYOlmg+tONGv9TRshu81HueJunbUGjJ0HsJvd47rsPQDaTrR
    39. yzmBRMD2wymVQ62VwF2dKTewWsy4gvgtO/gQguECgYEAnZSrDIirQZ+yOXuaA0qN
    40. 1yZMYKQQ7FcZf7c9heI1Eot5saAtCyapszO0cCN7pFw/TFPknrOz3I9cgmjJg7Br
    41. M7pfBTxJ0oMRjKdcMXpM88q9SwEpXyxZmL3rU2sq+zIAQfcYndAXXvVYeuUbGuHP
    42. Z8xRRviBTLKiOVc5NxJ0rqg=
    43. -----END RSA PRIVATE KEY-----'); // private key
    44. echo base64_encode($ciphertext) . "<br>";
    45. echo $rsa->decrypt($ciphertext);
    46. ?>
    Ich habe diesbezüglich mal einen Beitrag verfasst.
    Diesen findet Ihr dort:
    Lizenzsystem mit RSA-Signaturen

    Gibt's auch auf GibHub zusammen mit dem Quellcode:
    github.com/nikeee/license-system/blob/master/README.md
    Von meinem iPhone gesendet