Шифрование AES для NSString на iPhone
-
05-07-2019 - |
Вопрос
Кто-нибудь может указать мне правильное направление, чтобы иметь возможность зашифровать строку, возвращая другую строку с зашифрованными данными? (Я пробовал с шифрованием AES256.) Я хочу написать метод, который принимает два экземпляра NSString, один из которых является сообщением для шифрования, а другой - «паролем» для его шифрования - я подозреваю, что мне нужно сгенерировать ключ шифрования с паролем, который можно перевернуть, если пароль снабжен зашифрованными данными. Затем метод должен вернуть строку NSString, созданную из зашифрованных данных.
Я попробовал технику, описанную в первый комментарий к этому посту , но мне пока не повезло. В CryptoExercise Apple, безусловно, есть что-то, но я не могу понять это. .. Я видел много ссылок на CCCrypt , но в каждом случае, когда я его использовал, он не удался.
Мне также нужно было бы иметь возможность расшифровывать зашифрованную строку, но я надеюсь, что это так же просто, как kCCEncrypt / kCCDecrypt.
Решение
Поскольку вы еще не опубликовали код, трудно точно определить, с какими проблемами вы сталкиваетесь. Тем не менее, сообщение в блоге, на которое вы ссылаетесь, похоже, работает довольно прилично ... кроме лишней запятой в каждом вызове CCCrypt ()
, которая вызывала ошибки компиляции.
Более поздний комментарий к этому посту включает в себя этот адаптированный код , который работает для меня и кажется немного более простой. Если вы включите их код для категории NSData, вы можете написать что-то вроде этого: (Примечание: вызовы printf ()
предназначены только для демонстрации состояния данных в различных точках & # 8212; в реальное приложение, не имеет смысла печатать такие значения.)
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;
}
Учитывая этот код и тот факт, что зашифрованные данные не всегда хорошо переводятся в строку NSString, может оказаться более удобным написать два метода, которые обертывают необходимую вам функциональность, в прямом и обратном направлении ...
- (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];
}
Это определенно работает на Snow Leopard, и @Boz сообщает, что CommonCrypto является частью базовой ОС на iPhone. И в 10.4, и в 10.5 есть / usr / include / CommonCrypto
, хотя в 10.5 есть справочная страница для CCCryptor.3cc
, а в 10.4 нет, поэтому YMMV.
РЕДАКТИРОВАТЬ . этот дополнительный вопрос об использовании кодировки Base64 для представления зашифрованных байтов данных. в виде строки (при желании) с использованием безопасных преобразований без потерь.
Другие советы
Я собрал коллекцию категорий для NSData и NSString, которые используют решения, найденные на блог Джеффа Ламарша и некоторые подсказки Куинна Тейлора здесь, в Переполнении стека.
Он использует категории для расширения NSData, чтобы обеспечить шифрование AES256, а также предлагает расширение NSString для шифрования BASE64-кодированных данных безопасным способом в строки.
Вот пример, демонстрирующий использование для шифрования строк:
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] );
Получите полный исходный код здесь:
Спасибо за все полезные советы!
- Майкл
@owlstead, касательно вашего запроса на "криптографически безопасный вариант одного из приведенных ответов", " см. RNCryptor . Он был разработан для выполнения именно того, что вы запрашиваете (и был создан в ответ на проблемы с кодом, перечисленным здесь).
RNCryptor использует PBKDF2 с солью, обеспечивает случайное IV и присоединяет HMAC (также сгенерированный из PBKDF2 со своей собственной солью. Он поддерживает синхронную и асинхронную работу.
Я немного подождал на @QuinnTaylor, чтобы обновить его ответ, но так как он этого не сделал, вот ответ немного яснее и таким образом, что он будет загружен в XCode7 (и, возможно, лучше). Я использовал это в приложении Какао, но, скорее всего, оно будет хорошо работать и с приложением iOS. Не содержит ошибок ARC.
Вставьте перед любым разделом @implementation в файле AppDelegate.m или AppDelegate.mm.
#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
Вставьте эти две функции в желаемый класс @implementation. В моем случае я выбрал @implementation AppDelegate в своем файле AppDelegate.mm или AppDelegate.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];
}