AES string encryption in Objective-C
My Objective-C App requires text / string encryption (specifically nsstring).
I know AES is the most secure encryption method available for consumer use. I also understand how to convert strings to data and back... (just a beginner).
Many webpages and Q/As about encryption with AES are unclear, and none of them state how to use the code given. For example, a webpage might say: "here is the code... here is what it does..." but no explanation for how to use it.
I've found this code through lots of research:
#import "<CommonCrypto/CommonCryptor.h>"
@implementation NSMutableData(AES)
For encryption:
- (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;
}
For Decryption:
- (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;
}
}
This is the code I made that I would like to correspond with the above code:
- (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
}
How do I use this code, these methods? Where does it go in my Implementation file?
Solution 1:
This line near the top says you're adding AES functionality to NSMutableData:
@implementation NSMutableData(AES)
In Objective-C, this is called a category; categories let you extend an existing class.
This code would typically go in a file named NSMutableData-AES.m. Create a header file too, NSMutableData-AES.h. It should contain:
@interface NSMutableData(AES)
- (NSMutableData*) EncryptAES: (NSString *) key;
@end
Include (#import) that header in your main file. Add a call to the encryption function in your code:
NSData *InputData = [Input dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [InputData EncryptAES:@"myencryptionkey"];
Similarly for decryption.
Solution 2:
Since this appears to have been ignored so far:
CCCryptorStatus result = CCCrypt( kCCDecrypt , kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
**NULL**,
[self mutableBytes], [self length],
buffer_decrypt, bufferSize,
&numBytesEncrypted );
From the header file CommonCrypto/CommonCryptor.h:
@param iv Initialization vector, optional. Used by block ciphers when Cipher Block Chaining (CBC) mode is enabled. If present, must be the same length as the selected algorithm's block size. If CBC mode is selected (by the absence of the kCCOptionECBMode bit in the options flags) and no IV is present, a NULL (all zeroes) IV will be used. This parameter is ignored if ECB mode is used or if a stream cipher algorithm is selected.
The NULL in bold corresponds to the IV. Sadly, whoever designed the API made it optional. This makes this CBC mode essentially equivalent to ECB, which is not recommended for a variety of reasons.
Solution 3:
I got success using AES with the codes below:
Header file
#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
Implementation file
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]);
Finally, the tests outputs:
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
My repo on github with this examples: https://github.com/juliancorrea/aes-crypto-android-and-ios