Подтвердить что ты не робот

Шифрование AES256 NSString в iOS

Мое приложение шифрует и расшифровывает (или должно) NSString (текст, который нужно зашифровать/дешифровать) с помощью другого NSString (ключевое слово), используя aes 256-битное шифрование. Когда я запускаю проект и запускаю метод шифрования, ничто не зашифровывается, только текстовое поле просто очищается. Вот код, который у меня есть:

-(void)EncryptText {
    //Declare Keyword and Text
    NSString *plainText = DataBox.text;
    NSString *keyword = Keyword.text;

    //Convert NSString to NSData
    NSData *plainData = [plainText dataUsingEncoding:NSUTF8StringEncoding];

    //Encrypt the Data
    NSData *encryptedData = [plainData AESEncryptWithPassphrase:keyword];

    //Convert the NSData back to NSString
    NSString* cypherText = [[NSString alloc] initWithData:encryptedData encoding:NSUTF8StringEncoding];

    //Place the encrypted sting inside the Data Box
    NSLog(@"Cipher Text: %@", cypherText);
}

Заголовочные файлы можно скачать, нажав на эту ссылку: ZIP файл, содержащий AES-реализацию

Мне сказали, что мне нужно использовать кодировку Base-64 для моей строки, чтобы получить какой-либо результат. Если это так, то как это сделать?

Мне также сказали, что шифрование изменено в iOS 5, а мое приложение - приложение iOS 5+ ONLY. Если это так, то что мне нужно сделать, чтобы сделать это шифрование на iOS 5 или где я могу найти еще одну 256-битную реализацию AES, которая будет работать на NSString.

Почему этот код не создает результат?

4b9b3361

Ответ 1

EDIT: ссылки ниже относятся к более старой версии. Последняя версия называется RNCryptor.

В вашем коде не используется встроенная реализация AES iOS. Он имеет свою собственную реализацию. AESEncryptWithPassphrase: также неправильно генерирует ключ, отбрасывая большую часть энтропии в ключевой фразе.

В iOS вы должны использовать функции CCCrypt*() для AES. Вы также должны убедиться, что вы понимаете, что происходит в ваших процедурах шифрования и дешифрования. Очень легко написать код шифрования, который выглядит правильно (в том, что вы не можете прочитать вывод путем проверки), но крайне небезопасен.

См. Правильное шифрование с помощью AES с CommonCrypto для объяснения проблем с вышеупомянутой реализацией и правильного использования AES в iOS. Обратите внимание, что iOS 5 теперь имеет CCKeyDerivationPBKDF.

Нет необходимости, чтобы Base-64 кодировал вашу строку до шифрования. Кодирование Base-64 используется в тех случаях, когда вам необходимо преобразовать двоичные данные в форму, которую можно легко отправить по электронной почте или в другие места, где контрольные символы будут проблемой. Он преобразует 8-битные двоичные данные в 7-битные данные ASCII. Это не нужно или полезно здесь.


РЕДАКТИРОВАТЬ. Очень важно внимательно прочитать объяснение того, как использовать этот код. Опасно просто вырезать и вставить код безопасности и надеяться, что он сработает. Тем не менее, полный источник RNCryptManager доступен как часть примера кода главы 11 для iOS 5 Programming Pushing the Limits и может быть полезен [EDIT: это старый код; Я рекомендую RNCryptor сейчас, связанный в верхней части ответа]. Книга (которая должна быть доступна на следующей неделе, несмотря на то, что говорит сайт) включает гораздо более длительное обсуждение того, как использовать этот код, в том числе, как повысить производительность и иметь дело с очень большими наборами данных.

Ответ 2

NSData с категорией, отлично подходящей для AES-шифрования, я не проверял zip файл, но это должно сработать для вас;

#import <CommonCrypto/CommonCryptor.h>
@implementation NSData (AESAdditions)
- (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 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 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

Используйте его функции-обертки, например:

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