Шифрование строки AES в Objective-C

My Objective-C Приложение требует шифрования текста/строки (в частности nsstring).

Я знаю, что AES - самый безопасный метод шифрования, доступный для использования потребителями. Я также понимаю, как преобразовать строки в данные и обратно... (только новичок).

Многие веб-страницы и Q/As о шифровании с AES неясны, и ни один из них не указывает, как использовать указанный код. Например, веб-страница может сказать: "вот код... вот что он делает...", но не объясняет, как его использовать.

Я нашел этот код через множество исследований:

#import "<CommonCrypto/CommonCryptor.h>"
@implementation NSMutableData(AES)

Для шифрования:

- (NSMutableData*) EncryptAES:(NSString *)key {
    char keyPtr[kCCKeySizeAES256+1];
    bzero( keyPtr, sizeof(keyPtr) );

    [key getCString: keyPtr maxLength: sizeof(keyPtr) encoding: NSUTF16StringEncoding];
    size_t numBytesEncrypted = 0;

    NSUInteger dataLength = [self length];

    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    NSMutableData *output = [[NSData alloc] init];

    CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES256, NULL, [self mutableBytes], [self length], buffer, bufferSize, &numBytesEncrypted);

    output = [NSMutableData dataWithBytesNoCopy:buffer length:numBytesEncrypted];

    if(result == kCCSuccess) {
        return output;
    }
        return NULL;
    }

Для расшифровки:

- (NSMutableData*)DecryptAES: (NSString*)key andForData:(NSMutableData*)objEncryptedData {

    char  keyPtr[kCCKeySizeAES256+1];
    bzero( keyPtr, sizeof(keyPtr) );

    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF16StringEncoding];

    size_t numBytesEncrypted = 0;

    NSUInteger dataLength = [self length];

    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer_decrypt = malloc(bufferSize);    
    NSMutableData *output_decrypt = [[NSData alloc] init];
    CCCryptorStatus result = CCCrypt(kCCDecrypt , kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES256, NULL, [self mutableBytes], [self length], buffer_decrypt, bufferSize, &numBytesEncrypted);

    output_decrypt = [NSMutableData dataWithBytesNoCopy:buffer_decrypt length:numBytesEncrypted];

    if(result == kCCSuccess) {
        return output_decrypt;
    } 
        return NULL;
    }
}

Это код, который я сделал, который хотел бы соответствовать приведенному выше коду:

- (void)Encrypt {
    //Convert NSString to NSData so that it can be used to encrypt the Input
    NSString *Input  = [Inputbox text];
    NSData *InputData = [Input dataUsingEncoding:NSUTF8StringEncoding];
    //What to do here
}

Как использовать этот код, эти методы? Где это происходит в моем файле реализации?

Ответ 1

Эта строка в верхней части говорит о том, что вы добавляете функциональность AES в NSMutableData:

@implementation NSMutableData(AES)

В Objective-C это называется категорией; категории позволяют расширять существующий класс.

Этот код обычно входит в файл с именем NSMutableData-AES.m. Создайте файл заголовка, NSMutableData-AES.h. Он должен содержать:

@interface NSMutableData(AES)
- (NSMutableData*) EncryptAES: (NSString *) key;
@end

Включить (#import) этот заголовок в ваш основной файл. Добавить вызов функции шифрования в код:

NSData *InputData = [Input dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [InputData EncryptAES:@"myencryptionkey"];

Аналогично для расшифровки.

Ответ 2

Так как это пока что игнорировалось:

CCCryptorStatus result = CCCrypt( kCCDecrypt , kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                 keyPtr, kCCKeySizeAES256,
                                 **NULL**,
                                 [self mutableBytes], [self length],
                                 buffer_decrypt, bufferSize,
                                 &numBytesEncrypted );

Из файла заголовка CommonCrypto/CommonCryptor.h:

@param iv Вектор инициализации, необязательный. Использован                             блочные шифры, когда цепочка блоков шифрования (CBC)                             режим включен. Если они присутствуют, они должны быть одинаковыми                             как выбранный размер блока алгоритма.                             Если выбран режим CBC (из-за отсутствия                             бит kCCOptionECBMode в флажках параметров), и нет                             IV присутствует, будет использоваться NULL (все нули) IV.                             Этот параметр игнорируется, если используется режим ECB или                             если выбран алгоритм шифрования потока.

Значение NULL, выделенное жирным шрифтом, соответствует IV. К сожалению, любой, кто проектировал API, сделал его необязательным. Это делает этот режим CBC по существу эквивалентным ECB, который не рекомендуется по целому ряду причин.

Ответ 3

Я получил успех, используя AES с кодами ниже:

Заголовочный файл

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCryptor.h>

NS_ASSUME_NONNULL_BEGIN

@interface SecurityUtils : NSObject

+ (NSString *)encrypt:(NSString *)plainText error:(NSError **)error;
+ (NSString *)decrypt:(NSString *)plainText error:(NSError **)error;

@end

NS_ASSUME_NONNULL_END

Файл реализации

NSString *const IV = @"AEE0515D0B08A4E4";
NSString *const KEY =  @"9336565521E5F082BB5929E8E033BC69";


#import "SecurityUtils.h"


@implementation SecurityUtils


+ (NSString *)encrypt:(NSString *)plainText error:(NSError **)error {
    NSMutableData *result =  [SecurityUtils doAES:[plainText dataUsingEncoding:NSUTF8StringEncoding] context: kCCEncrypt error:error];
    return [result base64EncodedStringWithOptions:0];
}


+ (NSString *)decrypt:(NSString *)encryptedBase64String error:(NSError **)error {
    NSData *dataToDecrypt = [[NSData alloc] initWithBase64EncodedString:encryptedBase64String options:0];
    NSMutableData *result = [SecurityUtils doAES:dataToDecrypt context: kCCDecrypt error:error];
    return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];

}

+ (NSMutableData *)doAES:(NSData *)dataIn context:(CCOperation)kCCEncrypt_or_kCCDecrypt error:(NSError **)error {
        CCCryptorStatus ccStatus   = kCCSuccess;
        size_t          cryptBytes = 0;
        NSMutableData  *dataOut    = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeBlowfish];
        NSData *key =[KEY dataUsingEncoding:NSUTF8StringEncoding];
        NSData *iv = [IV dataUsingEncoding:NSUTF8StringEncoding];

        ccStatus = CCCrypt( kCCEncrypt_or_kCCDecrypt,
                           kCCAlgorithmAES,
                           kCCOptionPKCS7Padding,
                           key.bytes,
                           key.length,
                           (iv)?nil:iv.bytes,
                           dataIn.bytes,
                           dataIn.length,
                           dataOut.mutableBytes,
                           dataOut.length,
                           &cryptBytes);

        if (ccStatus == kCCSuccess) {
            dataOut.length = cryptBytes;
        }
        else {
            if (error) {
                *error = [NSError errorWithDomain:@"kEncryptionError"
                                             code:ccStatus
                                         userInfo:nil];
            }
            dataOut = nil;
        }

        return dataOut;
}


@end

IOS TESTING

NSError *error;
NSString *encrypted = [SecurityUtils encrypt:@"My Secret Text" error:&error];
NSLog(@"encrypted: %@",encrypted);
NSLog(@"decrypted: %@",[SecurityUtils decrypt:encrypted error:&error]);

Наконец, результаты тестов:

IOS OUTPUT

2019-05-16 21:38:02.947043-0300 MyApp[63392:1590665] encrypted: EJ41am5W1k6fA7ygFjTSEw==
2019-05-16 21:38:02.947270-0300 MyApp[63392:1590665] decrypted: My Secret Text