Reputation: 8608
My Objective-C app needs to do string
encryption (specifically nsstring).
I've found that AES is the most secure encryption methodology available for consumer use. I also have an understanding of how to convert strings to NSData
and back... (just a beginner). Unfortunately many webpages and Q&As about encryption with AES are unclear. None of them state how to use the code given.
This may be less of an "encryption" question, and more of a "how do I use these methods" question, so please bear with me.
I've found these example methods to encrypt and decrypt an NSString
:
#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 a method I wrote that I would like to use with the above methods:
- (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 the encryptAES
and decryptAES
methods? Where do they go in my implementation file?
Upvotes: 12
Views: 20082
Reputation: 1
+ (NSString*)encryptFileAtPath:(NSString *)inputFilePath outputPath:(NSString *)outputFilePath password:(NSString *)password {
// Convert the URL to a local file path
// Use the converted local file path to read the input data
NSData *inputData = [NSData dataWithContentsOfFile:inputFilePath];
if (!inputData) {
NSLog(@"Failed to read input file.");
return @"";
}
// Generate the key and IV from the password using PBKDF2 (same as in encryption)
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *keyData = [NSMutableData dataWithLength:kCCKeySizeAES256];
NSMutableData *ivData = [NSMutableData dataWithLength:kCCBlockSizeAES128];
// Use the same salt and rounds as in encryption
const char myByteArray[] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
NSData *salt = [NSData dataWithBytes:myByteArray length:32];
unsigned int rounds = 50000;
CCKeyDerivationPBKDF(kCCPBKDF2, passwordData.bytes, passwordData.length, [salt bytes], [salt length], 0, rounds, keyData.mutableBytes, keyData.length);
// Set up the decryption context with CBC mode
CCCryptorRef cryptor;
CCCryptorStatus status = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding | kCCOptionECBMode,
keyData.bytes, keyData.length, ivData.bytes, &cryptor);
if (status == kCCSuccess) {
NSMutableData *outputData = [NSMutableData dataWithLength:inputData.length + kCCBlockSizeAES128];
size_t encryptedLength;
// Perform encryption
status = CCCryptorUpdate(cryptor, inputData.bytes, inputData.length, outputData.mutableBytes, outputData.length, &encryptedLength);
if (status == kCCSuccess) {
// Finalize encryption
size_t finalLength;
status = CCCryptorFinal(cryptor, outputData.mutableBytes + encryptedLength, outputData.length - encryptedLength, &finalLength);
// [outputData setLength:encryptedLength + finalLength];
if (status == kCCSuccess) {
// Write encrypted data to the output file
NSString *outputFileName = [inputFilePath lastPathComponent];
NSURL *outPath = [NSURL URLWithString:outputFilePath];
NSString *trimmedFilePaths = [outPath.absoluteString containsString:@"file://"] == YES? [outPath.absoluteString stringByReplacingOccurrencesOfString:@"file://" withString:@""]: outPath.absoluteString;
NSString *trimmedD = [trimmedFilePaths containsString:@"%20"] == YES? [trimmedFilePaths stringByReplacingOccurrencesOfString:@"%20" withString:@" "]: trimmedFilePaths;
NSString *outputFileSPath = [trimmedD stringByAppendingPathComponent:outputFileName];
[outputData writeToFile:outputFileSPath atomically:YES];
NSLog(@"File encrypted successfully: %@", outputFilePath);
return outputFileSPath;
} else {
NSLog(@"Encryption finalization error: %d", status);
}
} else {
NSLog(@"Encryption update error: %d", status);
}
CCCryptorRelease(cryptor);
} else {
NSLog(@"Cryptor creation error: %d", status);
}
return @"";
}
Upvotes: 0
Reputation: 47
In my case above given code was not working. It was showing error regarding "kCCBufferTooSmall errorCode = -4301". I have to change it bit,if above code is not working please try it
+ (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 + kCCKeySizeAES256];
NSData *key =[encryptionNewKey dataUsingEncoding:NSUTF8StringEncoding];
NSData *iv = [encryptionIV dataUsingEncoding:NSUTF8StringEncoding];
ccStatus = CCCrypt( kCCEncrypt_or_kCCDecrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
key.bytes,
kCCKeySizeAES256,
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;
}
Hope can help someone
Upvotes: 0
Reputation: 668
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
Upvotes: 2
Reputation: 196
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.
Upvotes: 6
Reputation: 23398
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.
Upvotes: 7