Шифрование 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.
Почему этот код не создает результат?
Ответы
Ответ 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];
}