AES verschlüsselten String (PHP-seitig) via HTTP Request an iPhone App senden und entschlüsseln

  • AES verschlüsselten String (PHP-seitig) via HTTP Request an iPhone App senden und entschlüsseln

    Hallo!

    Ich habe heute ein sehr interessantes Problem.
    Momentan befasse ich mich mit der AES Verschlüsselnung.

    Wie ich mit einem PHP-Skript verschlüsseln und entschlüsseln kann ist mir klar.

    In ObjC in meinem iPhone App kann ich das auch.


    Allerdings möchte ich nun via HTTP-Request von dem iPhone App aus eine Anfrage an das PHP-Skript senden.
    Das PHP-Skript soll mir die Anwort mittels AES-Verschlüsselung verschlüsseln und an meine App die Antwort senden.

    Die App soll erhaltenen String dann entschlüsseln und erstmal in der Konsole ausgeben.


    Ansich ist das Ganze ja schon sehr spannend.


    Allerdings habe ich noch Probleme den verschlüsselten Antwort-String zu entschlüsseln.

    Nachfolgend mal mein Code:


    PHP-Quellcode

    1. /* HTTP Request aus der iPhone App */
    2. NSURL *phpSkript = [NSURL URLWithString:@"http://pfad/index.php"];
    3. NSURLRequest *anfrage = [NSURLRequest requestWithURL:phpSkript];
    4. NSURLResponse *antwort = nil;
    5. NSError *fehler = nil;
    6. NSData *empfangeneDaten = [NSURLConnection sendSynchronousRequest:anfrage
    7. returningResponse:&antwort
    8. error:&fehler];
    9. NSString *ans = [[NSString alloc] initWithData:empfangeneDaten encoding:NSUTF8StringEncoding];
    10. // ans: kUDKTSMo6qP1gsZXx1Zlc/xWCAs9AuYhaQbgFv5N9fk=
    11. if (fehler == nil) {
    12. if (ans != nil) {
    13. ...
    14. // AES 256 bit
    15. NSString *key = @"65t4jh%&ghjrbfjdghdjvhfjdfbvnvhj"; // 32 bit key
    16. NSData *strToNSData = [ans dataUsingEncoding:NSUTF8StringEncoding];
    17. NSLog(@"-> strToNSData: %@", strToNSData);
    18. NSString *decryptDataToNSString = [[[NSString alloc] initWithData:[AES256bit decryptData:strToNSData withKey:key]
    19. encoding:NSUTF8StringEncoding] autorelease];
    20. NSLog(@">>>>>>>> encryptStringToNSData -> decryptDataToNSString (unverschlüsselt): %@", decryptDataToNSString); // ??? NULL ???
    Alles anzeigen


    Der String wird php-seitig mit dem gleichen Passwort verschlüsselt.
    Habe ich einen String in ObjC verschlüsselt, so lässt er sich auch wieder korrekt entschlüsseln.
    Nur mit dem verschlüsselten "php-String" funktioniert das nicht.

    Nachfolgend das php-Skript:

    PHP-Quellcode

    1. $key256 = '65t4jh%&ghjrbfjdghdjvhfjdfbvnvhj'; // Das gleiche Passwort wie in ObjC
    2. $encryptData = fnEncrypt("Das ist ein verschlüsselter String zum Testen!", $key256);
    3. echo $encryptData;
    4. function fnEncrypt($sValue, $sSecretKey)
    5. {
    6. return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,
    7. $sSecretKey, $sValue, MCRYPT_MODE_ECB,
    8. mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,
    9. MCRYPT_MODE_ECB), MCRYPT_RAND))));
    10. }
    Alles anzeigen


    Nachfolgend noch der ObjC code zum entschlüsseln:

    PHP-Quellcode

    1. #import "NSData-AES.h"
    2. + (NSData*) decryptData:(NSData*)ciphertext withKey:(NSString*)key;
    3. {
    4. // Methodenaufruf in NSData-AES.h zum entschlüsseln des Strings
    5. return [ciphertext AES256DecryptWithKey:key];
    6. }
    7. #import "NSData-AES.h"
    8. #import <CommonCrypto/CommonCryptor.h>
    9. - (NSData *)AES256DecryptWithKey:(NSString *)key {
    10. // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    11. char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
    12. bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
    13. // fetch key data
    14. [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    15. NSUInteger dataLength = [self length];
    16. //See the doc: For block ciphers, the output size will always be less than or
    17. //equal to the input size plus the size of one block.
    18. //That's why we need to add the size of one block here
    19. size_t bufferSize = dataLength + kCCBlockSizeAES128;
    20. void *buffer = malloc(bufferSize);
    21. size_t numBytesDecrypted = 0;
    22. CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
    23. keyPtr, kCCKeySizeAES256,
    24. NULL, // initialization vector (optional)
    25. [self bytes], dataLength, // input
    26. buffer, bufferSize, // output
    27. &numBytesDecrypted);
    28. if (cryptStatus == kCCSuccess) {
    29. //the returned NSData takes ownership of the buffer and will free it on deallocation
    30. return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    31. }
    32. free(buffer); //free the buffer;
    33. return nil;
    34. }
    35. }
    36. }
    Alles anzeigen


    Ich komme hier einfach nicht weiter.
    Hat von euch jmd Erfahrung mit der AES-Verschlüsselung?

    Das Zusammenspiel zwischen dem PHP-Skript und der iPhone App in ObjC funktioniert bei mir nicht.


    Ich bin über jede Hilfe und Anregung sehr Dankbar!

    Gerne werde ich von der erarbeiteten Lösung eine kurze Zusammenfassung hinterlassen.


    Vielen Dank euch allen!


    Schönen Gruss! :)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von OsnaTiger ()

  • Wäre auch meine erste Idee, dass PHP einen anderen Zeichensatz nimmt. Probiere doch mal in beiden Fällen reine Bytes zu encrypten? Auch das encoding vom Key könnte ein Problem sein, Du hast zwar nicht sonderlich Sonderzeichen drin, aber versuch halt mal einen 0-Key oder so.

    Du kannst mal schauen, hier gibt es Test-Vektoren:
    csrc.nist.gov/groups/STM/cavp/documents/aes/KAT_AES.zip

    Prüfe damit mal, wer unter den dort gegeben Keys und IVs den auch dort gegebenen Ciphertext erzeugt. Dann weisst Du schonmal, wo Du genauer schauen musst.
    C++
  • Vielen Dank für eure Hinweise.

    Allerdings frage ich mich gerade ob mein PHP Skript auch wirklich richtig arbeitet.

    PHP-Quellcode

    1. $key256 = '00000000000000000000000000000000';
    2. $encryptData = fnEncrypt("f34481ec3cc627bacd5dc3fb08f273e6", $key256);
    3. //echo $encryptData;
    4. echo "encrypt: ".$encryptData;
    5. echo "</br>";
    6. echo "decrypt: ".fnDecrypt($encryptData, $key256);
    7. function fnEncrypt($sValue, $sSecretKey)
    8. {
    9. return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,
    10. $sSecretKey, $sValue, MCRYPT_MODE_ECB,
    11. mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,
    12. MCRYPT_MODE_ECB), MCRYPT_RAND))));
    13. }
    14. function fnDecrypt($sValue, $sSecretKey)
    15. {
    16. return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sSecretKey,
    17. base64_decode($sValue), MCRYPT_MODE_ECB,
    18. mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,
    19. MCRYPT_MODE_ECB), MCRYPT_RAND)));
    20. }
    21. OUTPUT
    22. =======
    23. ncrypt: x1J9alr7kXrg337IA5iZ9M9Bx3Zpcr+IwKn6+8Li334=
    24. decrypt: f34481ec3cc627bacd5dc3fb08f273e6
    Alles anzeigen
  • Noch was: In deinem PHP Code nimmst Du ECB. Das ist eigentlich nicht so klug. Und wenn Deine Obj-C Implementation CBC nimmt, passt es auch nicht zusammen. Hab grad noch nicht herausgefunden, was der default bei CommonCrypto ist, aber ich würde sogar fast auf CBC tippen.
    Tausch also am besten mal das unsägliche ECB in Deinem PHP Code gegen CBC

    EDIT
    Noch ein paar Punkte:
    - Für CBC muss beiden Seiten der gleich IV bekannt sein
    - Im PHP machst Du base64 encoding/decoding, in Objective-C fehlt das einfach!
    - Schau mal hier: php.net/manual/de/function.mcrypt-encrypt.php#69580
    - Ein bisschen in Kryptographie einlesen wäre nicht schlecht ;)
    C++

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von zerm ()

  • Habe da ein wenig was herausgefunden.

    Standard beim CommonCrypto ist CBC:
    Der ECB ist optional.

    PHP-Quellcode

    1. /*!
    2. @enum CCOptions
    3. @abstract Options flags, passed to CCCryptorCreate().
    4. @constant kCCOptionPKCS7Padding Perform PKCS7 padding.
    5. @constant kCCOptionECBMode Electronic Code Book Mode.
    6. Default is CBC.
    7. */
    8. enum {
    9. /* options for block ciphers */
    10. kCCOptionPKCS7Padding = 0x0001,
    11. kCCOptionECBMode = 0x0002
    12. /* stream ciphers currently have no options */
    13. };
    Alles anzeigen
  • Ich habe da auch noch eine kleine Baustelle in ObjC Code.

    Wenn ich einen String AES verschlüssel und NSData dann in einen NSString convertiere ...

    Quellcode

    1. NSString *key = @"00000000000000000000000000000000"; // 32 bit key
    2. // String zum verschlüsseln
    3. NSString *str = @"f34481ec3cc627bacd5dc3fb08f273e6";
    4. NSData *strToNSData = [NSData dataWithData: [str dataUsingEncoding: NSUTF8StringEncoding]];
    5. NSLog(@"-> encryptNSDataToNSString (verschlüsselt): %@", [[[NSString alloc] initWithData:encryptNSData encoding:NSASCIIStringEncoding] autorelease]);


    Erhalte ich folgendes:

    Quellcode

    1. -> encryptNSDataToNSString (verschlüsselt): ]ÐÏG¾•‰*V¸¿¯S$ð;˜bÀƑŒÐ™]@Ç»a


    Die Ausgabe sieht in der Konsole noch etwas anders aus.

    nutze ich das NSUTF8StringEncoding dann erhalte ich NULL.


    Auch hier habe ich im Forum und im Web nach einer Lösung gesucht ... oder zumindest nach einer Verständnisstütze.

    Entschlüssel ich das NSData Object wieder, so kann ich auch den NSString aus NSData konvertieren:

    Quellcode

    1. NSString *decryptDataToNSString = [[[NSString alloc] initWithData:[AES256bit decryptData:encryptNSData withKey:key] encoding:NSUTF8StringEncoding] autorelease];
    2. NSLog(@"encryptStringToNSData -> decryptDataToNSString (unverschlüsselt): %@", decryptDataToNSString);


    Das funktioniert auch problemlos.

    Ich schaffe es nur nicht den verschlüsselten NSString aus NSData zu extrahieren.
    Sehr gerne würde ich mir mal den verschlüsselten String in UTF8 anschauen in der Konsole.


    Könnt ihr mir bei dieser offenen Frage weiterhelfen?

    :)

    Vielen Dank für eure Hilfe^^
  • So wie ich die Sache sehe, wird da was verschlüsselt.
    Dass da kein sinnvoller Text bei raus kommt dürfte klar sein.
    ASCII und auch UTF-8/UTF-16 haben eine ganze Menge an Zeichen, die nicht oder nicht sinnvoll darstellbar sind.

    Was genau ist also deine Frage?
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Lucas de Vil schrieb:

    So wie ich die Sache sehe, wird da was verschlüsselt.
    Dass da kein sinnvoller Text bei raus kommt dürfte klar sein.
    ASCII und auch UTF-8/UTF-16 haben eine ganze Menge an Zeichen, die nicht oder nicht sinnvoll darstellbar sind.

    Was genau ist also deine Frage?

    Hey, danke für deine Antwort.

    Die Idee ist folgende.

    Ich möchte einen String verschlüsseln und diesen String dann via HTTP-Request an ein PHP Skript senden, welches den String dann wieder entschlüsselt und im Browser richtig darstellt.
    Das ist eine kleine Übung für mich.

    Möglich das ich hier einen falschen Ansatz verfolge.

    Ich möchte folgendes:

    (1) NSString plantext AES verschlüsseln
    (2) NSData *cipher = [plain AES256EncryptWithKey:key];
    (3) Aus NSData cipher in NSString convertieren
    (4) Via HTTP-Request an ein PHP-Skript senden
    (5) String entschlüsseln und im Browser den plantext ausgeben

    Wie ich in ObjC verschlüsseln und entschlüsseln kann ... auch Datein ist mir klar.

    Nur möchte ich nun auch einen AES verschlüsselten String an ein PHP Skript senden ... wie oben beschrieben. :)

    Beim PHP Skript kann ich den encrypt String doch auch ausgeben:

    PHP-Quellcode

    1. // Ausgabe im Browser
    2. encrypt: x1J9alr7kXrg337IA5iZ9M9Bx3Zpcr+IwKn6+8Li334= // Das erwarte ich auch in ObjC
    3. decrypt: f34481ec3cc627bacd5dc3fb08f273e6
    4. // Code
    5. $key256 = '00000000000000000000000000000000';
    6. $encryptData = fnEncrypt("f34481ec3cc627bacd5dc3fb08f273e6", $key256);
    7. //echo $encryptData;
    8. echo "encrypt: ".$encryptData;
    9. echo "</br>";
    10. echo "decrypt: ".fnDecrypt($encryptData, $key256);
    11. function fnEncrypt($sValue, $sSecretKey)
    12. {
    13. return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,
    14. $sSecretKey, $sValue, MCRYPT_MODE_ECB,
    15. mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,
    16. MCRYPT_MODE_ECB), MCRYPT_RAND))));
    17. }
    18. function fnDecrypt($sValue, $sSecretKey)
    19. {
    20. return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sSecretKey,
    21. base64_decode($sValue), MCRYPT_MODE_ECB,
    22. mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,
    23. MCRYPT_MODE_ECB), MCRYPT_RAND)));
    24. }
    Alles anzeigen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von OsnaTiger ()

  • Du bekommst Probleme, wenn Du den Ciphertext versuchst als String darzustellen. Beispielsweise darf der Ciphertext ja an einer beliebigen Stelle ein Null-Byte enthalten (Wenn die Verschlüsselung gut ist, muss sogar jedes Byte die Wahrscheinlichkeit von 1:256 habe, dass es genau 00 ist!). Von daher würde ich auch nicht mit NSString hantieren, und der Upload sollte auch multipart/form-data geschehen, also nicht ganz so trivial.
    Alternativ kannst Du den Ciphertext base64 encoden, wie das in dem PHP Beispiel schon so vorgesehen ist. Damit bekommst Du dann nur 7-Bit zeichen. Du kannst auch cool sein und UTF-7 nehmen, das ist dann mal eine kleine Abwechselung ;)
    C++
  • NSObject schrieb:

    UTF-7 !? Sehr geil! :D
    Zum Testen könnte man auch mal UUencode ausgraben.

    Na UTF-7 ist eine super Alternative zu base64 ;) Gabs auch mal diesen fiesen Exploit, wenn ich mich recht erinnere, hatte der Internet Explorer eine Webseite gerne auch als UTF-7 encoded interpretiert, wenn UTF-7 drin vorkam und keine weitere Encoding Direktive vorhanden war. So konnte man super <script> als UTF-7 unterschieben, was natürlich von keiner Webanwendung gefiltert wurde...
    C++
  • Vielen Dank euch allen für eure Hilfe.

    Das Zusammenspiel zwischen iPhone App (ObjC) und PHP-Skript -> verschlüsseln und entschlüsseln von NSString (AES256 bit) funktioniert nun bestens.

    In beide Richtungen lässt sich nun ein String verschlüsselt übetragen und entsprechend entschlüsseln.


    Morgen werde ich meine Lösung kurz skizzieren.

    Gerne können wir dann auch noch einmal über die Lösung diskutieren.

    Meine Lösung muss ja nicht unbedingt optimal sein :)



    Bis morgen dann!!
  • wolf_10de schrieb:

    Super, schreib doch mal ein Tutorial hier darüber, würden sich bestimmt welche freuen.

    Aber dann nicht vergessen darauf hinzuweisen, dass die Sicherheit stark von der genauen Nutzung abhängt: Beispielsweise ist es relativ trivial ein festes Passwort aus einer iPhone-Anwendung zu extrahieren. Wenn man das dann einmal hat, kann ein Angreifer etwa in einem öffentlichen WLAN alle Kommunikation des App-Nutzers mitlesen, als wäre sie im Klartext übertragen.
    C++