it-swarm.com.de

AES-Verschlüsselung für einen NSString auf dem iPhone

Kann mich jemand in die richtige Richtung weisen, um eine Zeichenfolge zu verschlüsseln und eine andere Zeichenfolge mit den verschlüsselten Daten zurückzugeben? (Ich habe versucht, mit AES256-Verschlüsselung zu arbeiten.) Ich möchte eine Methode schreiben, die zwei NSString-Instanzen benötigt, wobei eine die zu verschlüsselnde Nachricht und die andere ein 'Passcode' ist, mit dem sie verschlüsselt wird den Verschlüsselungsschlüssel mit dem Passcode in einer Weise, die umgekehrt werden kann, wenn der Passcode mit den verschlüsselten Daten geliefert wird. Die Methode sollte dann einen NSString zurückgeben, der aus den verschlüsselten Daten erstellt wurde.

Ich habe die in dem ersten Kommentar zu diesem Beitrag beschriebene Technik ausprobiert , aber ich hatte bisher kein Glück. Apples CryptoExercise hat sicherlich etwas, aber ich kann es nicht verstehen ... Ich habe viele Verweise auf CCCrypt , aber es ist in jedem Fall fehlgeschlagen, in dem ich es benutzt habe.

Ich müsste auch in der Lage sein, einen verschlüsselten String zu entschlüsseln, aber ich hoffe, das ist so einfach wie kCCEncrypt/kCCDecrypt.

123
Boz

Da Sie keinen Code gepostet haben, ist es schwierig, genau zu wissen, auf welche Probleme Sie stoßen. Der Blog-Beitrag, auf den Sie verlinken, scheint jedoch ziemlich anständig zu funktionieren ... abgesehen von dem zusätzlichen Komma bei jedem Aufruf von CCCrypt(), das Kompilierungsfehler verursachte.

Ein späterer Kommentar zu diesem Beitrag enthält diesen angepassten Code , der für mich funktioniert und etwas einfacher zu sein scheint. Wenn Sie den Code für die NSData-Kategorie angeben, können Sie Folgendes schreiben: (Hinweis: Die printf() -Aufrufe dienen nur dazu, den Status der Daten an verschiedenen Stellen zu veranschaulichen. In einer echten Anwendung würde dies nicht der Fall sein. ' Es ist nicht sinnvoll, solche Werte zu drucken.)

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSString *key = @"my password";
    NSString *secret = @"text to encrypt";

    NSData *plain = [secret dataUsingEncoding:NSUTF8StringEncoding];
    NSData *cipher = [plain AES256EncryptWithKey:key];
    printf("%s\n", [[cipher description] UTF8String]);

    plain = [cipher AES256DecryptWithKey:key];
    printf("%s\n", [[plain description] UTF8String]);
    printf("%s\n", [[[NSString alloc] initWithData:plain encoding:NSUTF8StringEncoding] UTF8String]);

    [pool drain];
    return 0;
}

Angesichts dieses Codes und der Tatsache, dass verschlüsselte Daten nicht immer gut in einen NSString übersetzt werden können, ist es möglicherweise praktischer, zwei Methoden zu schreiben, die die von Ihnen benötigten Funktionen in Vorwärts- und Rückwärtsrichtung umschließen ...

- (NSData*) encryptString:(NSString*)plaintext withKey:(NSString*)key {
    return [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
}

- (NSString*) decryptData:(NSData*)ciphertext withKey:(NSString*)key {
    return [[[NSString alloc] initWithData:[ciphertext AES256DecryptWithKey:key]
                                  encoding:NSUTF8StringEncoding] autorelease];
}

Dies funktioniert definitiv auf Snow Leopard und @ Boz meldet, dass CommonCrypto Teil des Core-Betriebssystems auf dem iPhone ist. Sowohl 10.4 als auch 10.5 haben /usr/include/CommonCrypto, Obwohl 10.5 eine Manpage für CCCryptor.3cc Hat und 10.4 nicht, also YMMV.


BEARBEITEN: Siehe diese Folgefrage zur Verwendung der Base64-Codierung zur Darstellung verschlüsselter Datenbytes als Zeichenfolge (falls gewünscht) unter Verwendung von sichere, verlustfreie Konvertierungen.

127
Quinn Taylor

Ich habe eine Sammlung von Kategorien für NSData und NSString zusammengestellt, die Lösungen verwendet, die in Jeff LaMarches Blog und einige Hinweise von Quinn Taylor hier auf Stack Overflow zu finden sind.

Es verwendet Kategorien, um NSData für die AES256-Verschlüsselung zu erweitern, und bietet auch eine Erweiterung von NSString für die sichere BASE64-Verschlüsselung verschlüsselter Daten für Zeichenfolgen.

Hier ist ein Beispiel, um die Verwendung zum Verschlüsseln von Zeichenfolgen zu zeigen:

NSString *plainString = @"This string will be encrypted";
NSString *key = @"YourEncryptionKey"; // should be provided by a user

NSLog( @"Original String: %@", plainString );

NSString *encryptedString = [plainString AES256EncryptWithKey:key];
NSLog( @"Encrypted String: %@", encryptedString );

NSLog( @"Decrypted String: %@", [encryptedString AES256DecryptWithKey:key] );

Den vollständigen Quellcode erhalten Sie hier:

https://Gist.github.com/838614

Vielen Dank für alle hilfreichen Tipps!

- Michael

45
Michael Thiel

@owlstead, in Bezug auf Ihre Anfrage nach "einer kryptografisch sicheren Variante einer der angegebenen Antworten" lesen Sie bitte RNCryptor . Es wurde entwickelt, um genau das zu tun, was Sie anfordern (und wurde als Reaktion auf die Probleme mit dem hier aufgeführten Code erstellt).

RNCryptor verwendet PBKDF2 mit Salt, stellt eine zufällige IV bereit und hängt HMAC (ebenfalls aus PBKDF2 mit einem eigenen Salt generiert) an. Es unterstützt den synchronen und asynchronen Betrieb.

34
Rob Napier

Ich habe ein bisschen auf @QuinnTaylor gewartet, um seine Antwort zu aktualisieren, aber da er es nicht getan hat, ist die Antwort hier ein bisschen klarer und so, dass sie auf XCode7 (und vielleicht höher) geladen wird. Ich habe dies in einer Cocoa-Anwendung verwendet, aber wahrscheinlich funktioniert es auch mit einer iOS-Anwendung. Hat keine ARC-Fehler.

Einfügen vor einem @ Implementierungsabschnitt in Ihrer AppDelegate.m- oder AppDelegate.mm-Datei.

#import <CommonCrypto/CommonCryptor.h>

@implementation NSData (AES256)

- (NSData *)AES256EncryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or 
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

- (NSData *)AES256DecryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or 
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesDecrypted);

    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

@end

Fügen Sie diese beiden Funktionen in die gewünschte @ Implementierungsklasse ein. In meinem Fall habe ich in meiner Datei AppDelegate.mm oder AppDelegate.m die Option @Implementation AppDelegate gewählt.

- (NSString *) encryptString:(NSString*)plaintext withKey:(NSString*)key {
    NSData *data = [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
    return [data base64EncodedStringWithOptions:kNilOptions];
}

- (NSString *) decryptString:(NSString *)ciphertext withKey:(NSString*)key {
    NSData *data = [[NSData alloc] initWithBase64EncodedString:ciphertext options:kNilOptions];
    return [[NSString alloc] initWithData:[data AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
}
10
Volomike