Szyfrowanie AES dla NSString na iPhone

Czy ktoś może wskazać mi właściwy kierunek, aby móc zaszyfrować ciąg znaków, zwracając inny ciąg z zaszyfrowanymi danymi? (Próbowałem z szyfrowaniem AES256.) Chcę napisać metodę, która zajmuje dwa instancje NSString, jeden jest wiadomość do zaszyfrowania, a drugi jest "hasło" do zaszyfrowania go z - podejrzewam, że będę musiał wygenerować klucz szyfrowania z hasłem, w sposób, który może być odwrócony, jeśli hasło jest dostarczane z zaszyfrowanych danych. Metoda powinna następnie zwraca NSString utworzony z zaszyfrowanych danych.

Wypróbowałem technikę opisaną w w pierwszym komentarzu do tego posta, ale do tej pory nie miałem szczęścia. Apple CryptoExercise na pewno coś ma, ale nie mogę tego zrozumieć... Widziałem wiele odniesień do CCCrypt , ale w każdym przypadku nie powiodło się.

Musiałbym również być w stanie odszyfrować zaszyfrowany ciąg znaków, ale mam nadzieję, że jest to tak proste, jak kCCEncrypt/kCCDecrypt.

Author: Quinn Taylor, 2009-09-09

4 answers

Ponieważ nie opublikowałeś żadnego kodu, trudno jest dokładnie wiedzieć, z jakimi problemami się spotykasz. Jednak post na blogu, do którego linkujesz, wydaje się działać całkiem przyzwoicie... pomijając dodatkowy przecinek w każdym wywołaniu CCCrypt(), który powodował błędy kompilacji.

Późniejszy komentarz do tego postu zawiera Ten zaadaptowany kod , który działa dla mnie i wydaje się nieco prostszy. Jeśli dodasz ich kod do kategorii NSData, możesz napisać coś takiego: (Uwaga: the printf() wywołania służą tylko do pokazania stanu danych w różnych punktach - w prawdziwej aplikacji drukowanie takich wartości nie miałoby sensu.)

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;
}

Biorąc pod uwagę ten kod i fakt, że zaszyfrowane dane nie zawsze będą ładnie przekładać się na NSString, może być wygodniej napisać dwie metody, które zawijają potrzebną funkcjonalność, w przód iw tył...

- (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];
}

To zdecydowanie działa na Snow Leopardzie, i@Boz donosi, że CommonCrypto jest częścią rdzenia OS na iPhonie. Zarówno 10.4, jak i 10.5 mają /usr/include/CommonCrypto, chociaż 10.5 ma stronę podręcznika dla CCCryptor.3cc, a 10.4 Nie, więc YMMV.


EDIT: Zobacz to kolejne pytanie na temat używania kodowania Base64 do reprezentowania zaszyfrowanych bajtów danych jako ciągu znaków (w razie potrzeby) przy użyciu bezpiecznych, bezstratnych konwersji.

 126
Author: Quinn Taylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:55

Zebrałem zbiór kategorii Dla NSData i NSString, które wykorzystują rozwiązania znalezione na blogu Jeffa LaMarche ' a i kilka wskazówek Quinn Taylor tutaj na Stack Overflow.

Używa kategorii do rozszerzenia nsdata w celu zapewnienia szyfrowania AES256, a także oferuje rozszerzenie NSString do Base64-encode szyfrowanych danych bezpiecznie do ciągów.

Oto przykład użycia do szyfrowania łańcuchów:

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] );

Pobierz Pełny kod źródłowy tutaj:

Https://gist.github.com/838614

Dzięki za wszystkie pomocne wskazówki!

-- Michael

 45
Author: Michael Thiel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:28

@owlstead, jeśli chodzi o Twoją prośbę o "kryptograficznie bezpieczny wariant jednej z podanych odpowiedzi", zobacz RNCryptor. Został zaprojektowany, aby robić dokładnie to, o co prosisz (i został zbudowany w odpowiedzi na problemy z kodem wymienionym tutaj).

RNCryptor używa PBKDF2 z solą, dostarcza losowo IV i dołącza HMAC (również generowany z PBKDF2 z własną solą. Obsługuje synchroniczną i asynchroniczną pracę.

 33
Author: Rob Napier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-14 19:44:33

Czekałem trochę na @ QuinnTaylor, aby zaktualizować swoją odpowiedź, ale ponieważ nie, oto odpowiedź trochę wyraźniej iw sposób, że będzie ładować XCode7(i być może większy). Użyłem tego w aplikacji Cocoa, ale prawdopodobnie będzie działać również z aplikacją iOS. Nie ma błędów łuku.

Wklej przed dowolnÄ… sekcjÄ… @ implementation w aplikacji.m lub AppDelegate.mm plik.

#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

Wklej te dwie funkcje do pożądanej klasy implementacji@. W moim przypadku wybrałem @ implementation AppDelegate w moim AppDelegate.mm lub AppDelegate.plik M.

- (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];
}
 7
Author: Volomike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-18 18:20:15