Cocoa AES Encryption NSData and Bytearrays - cocoa

I'm using the following code to encrypt files in cocoa:
- (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;
}
And wrote this for the connection to the file:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"foo" ofType:#"rtf"];
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSString *key = [withFileKey stringValue];
NSString *newStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSString *encrypted = [newStr AES256EncryptWithKey:key];
NSLog(#"File encryption:%#", encrypted);
[filePathName setStringValue:filePath];
if (!data) {
NSLog(#"Unable to read file");
}
Basically what I did was first of all get the filepath of the file the user wants. Then convert the data in the file to a string. Then encrypt that string with the AES256EncryptWithKey: method. However, when I decrypt a plain text file for example, it returns a bunch of garbage like fonts and all that stuff, then the few lines I wrote. Something like this:
\ansicpg1252\cocoartf1138\cocoasubrtf100
{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 Menlo-Bold;}
{\colortbl;\red255\green255\blue255;}
\margl1440\margr1440\vieww10800\viewh8400\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural
\f0\fs24 \cf0 Hello my name is bobby bob\
\
\pard\tx560\pardeftab560\pardirnatural
\f1\b\fs22 \cf0 \CocoaLigature0 YAY!\
and I am awesome!!}
Shouldn't I be taking the data and then encrypting that (conversion to bytes), then convert the encrypted data and convert it to a string to display? I tried something like that but it didn't work. :(
Something like:
NSData *encryptedData = [data AES256EncryptWithKey:yourkey];
And then:
NSString *convertData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
?
Your help is greatly appreciated. Thanks!

Your code appears hard-coded to load foo.rtf. This looks like an RTF file. Where is the "plain text file" you're talking about?
EDIT We had a lot of discussion on this, so I wrote up a blog post about how to correctly use CCCrypt().

Related

AES Encryption is not working (Xcode)

I'm trying to encrypt string in Xcode to PHP with AES128 method by using following code:
Xcode
- (NSData*)AES256EncryptWithKey:(NSString*)key {
char keyPtr[kCCKeySizeAES256];
[key cStringUsingEncoding:NSASCIIStringEncoding];
NSString *iv = #"fdsfds85435nfdfs";
char ivPtr[kCCKeySizeAES128];
[iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSASCIIStringEncoding];
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void* buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, NULL,
keyPtr, kCCKeySizeAES256,
ivPtr,
[self bytes], dataLength,
buffer, bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess)
{
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
But when I run above coding, following result is not what I expect to be:
NSString *key = #"89432hjfsd891787";
NSData *plaintext = [[#"aaa0000000000000" dataUsingEncoding:NSASCIIStringEncoding] AES256EncryptWithKey: key];
NSString *mystring = [[NSString alloc] initWithData:plaintext encoding:NSASCIIStringEncoding];
NSLog(#"mystring %#", mystring);
OUTPUT is
uçó)â½S/èRÅ
What I want it something like that.
m9FNGM9IiwibWFjIjoiNmJkYzNmZTA5
Note: due to a coding error the keyPtr is not set to the key value, it becomes the value of the uninitialized memory.
You get "uçó)â½S/èRÅ" because you try to create a string from the data and there are a couple reasons this will not work.
Many data bytes do not map to printable ASCII characters or to any unicode character.
A data byte can be 0 (1 in 256 bytes on average will be 0x00) and that is a terminator for a "C" string so the string will be short.
There are two general conventions for encoding data into a string representation:
Hex-ascii where each data byte is encoded into two characters 0-9a-f.
Base64 where each 3 data data bytes are encoded into 4 ASCII characters.
You are probably looking for Base64 encoding:
NSString *mystring = [plaintext base64EncodedStringWithOptions:0];
Other errors in the code:
[key cStringUsingEncoding:NSASCIIStringEncoding]; The string may not be ASCII, better to use NSUTF8StringEncoding. Note that the output is not captured.
The keyPtr is never set to the key value, see above.
The key size id specified as 256-bits (32-bytes) but the key is 16 characters, use a key size that matched the key.
char ivPtr[kCCKeySizeAES128], an iv size is the block size not the key size: kCCBlockSizeAES128.
Looks like you want a Base64 encoded string.
NSString *mystring = [plaintext base64EncodedStringWithOptions:0];

compressed CGImage with CGImageDestination truncated after getting bytes

I want to get the compressed data from a CGImageRef to send it over a network connection.
To do so, i use a CGImageDestinationRef (CGImageDestinationCreateWithData).
After pulling the Data out of the CFDataRef Object the image misses a couple of rows at the bottom.
Here is what i do (cleaned for reading purpose...):
CFImageRef image = getTheImageRefIWant();
CFMutableDataRef pngData = CFDataCreateMutable (kCFAllocatorDefault, 0);
CGImageDestinationRef dataDest = CGImageDestinationCreateWithData (pngData, kUTTypePNG, 1, NULL);
CGImageDestinationAddImage (dataDest, image, NULL); //also tried this with options...
CGImageDestinationFinalize (dataDest);
CFIndex len = CFDataGetLength(pngData);
//copy data
unsigned char* m_image = malloc(len);
CFDataGetBytes (pngData, CFRangeMake(0,len), m_image);
//save data - for testing purpose
FILE *file = fopen("/path/test.png", "wb");
fwrite(m_image, 1, len, file);
//adding header and stuff - skipped here...
//send data
send(sockfd, m_image, len, 0);
If i use the CFData Object as NSData Object and save it to disk it does work:
NSData *data = [(NSData *)pngData autorelease];
[data writeToFile:#"/path/test.png" atomically:YES];
but if is use NSDatas byte method, it is the same (truncated image):
NSUInteger len = [data length];
m_image = malloc(len);
memcpy(m_image, (unsigned char*)[data bytes], len);
seems the data in CFData Object seems to be ok.
But how to get the bytes properly?
Thanks for any advice.
Have you either fflush()ed or fclose()d the file after writing it? Your data may just be buffered in memory.

Implementing a file format to be used with Encryption - Cocoa

I need to implement salts in my encryption, but to do so, I need to store it in a file format that I need to create so I can later retrieve it to decrypt. I'm a noob when it comes to encryption. The specifications of the file format should be as so:
Ciphertext: length of ciphertext ;
Salt: length of salt ;
Then the ciphertext and salt written out. This is where xcode really confuses me, as in creating a new file, etc.
How can I do this? And then retrieve the salt for decryption?
Thank you, your help is greatly appreciated.
You might consider using NSMutableDictionary and NSKeyedUnarchiver like this:
// Example ciphertext and salt
NSString *ciphertext = #"the ciphertext";
NSString *salt = #"the salt";
// File destination
NSString *path = #"/Users/Anne/Desktop/Archive.dat";
// Create dictionary with ciphertext and salt
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:ciphertext forKey:#"ciphertext"];
[dictionary setObject:salt forKey:#"salt"];
// Archive dictionary and write to file
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dictionary];
[data writeToFile:path options:NSDataWritingAtomic error:nil];
// Read file and unarchive
NSMutableDictionary *theDictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
// Get ciphertext and salt
NSString *theCiphertext = [theDictionary objectForKey:#"ciphertext"];
NSString *theSalt = [theDictionary objectForKey:#"salt"];
// Show Result
NSLog(#"Extracted ciphertext: %#",theCiphertext);
NSLog(#"Extracted salt: %#",theSalt);
Output:
Extracted ciphertext: the ciphertext
Extracted salt: the salt
EDIT
Response to comment: Both NSData and NSString feature length.
Quick example:
NSString *theString = #"Example String";
NSData *theData = [theString dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger stringLength = [theString length];
NSUInteger dataLength = [theData length];
NSLog(#"String length: %ld",stringLength);
NSLog(#"Data length: %ld",dataLength);
Output:
String length: 14
Data length: 14

Trying to get bytes and append using NSMutableData for a video through Asset Library gives memory full error

I’m trying to upload a video of size 100MB through Asset Library. But when i try to use -(NSUInteger)getBytes:(uint8_t *)buffer fromOffset:(long long)offset length:(NSUInteger)length error:(NSError **)error of ALAssetRepresentation I get memory full error. I also need to put the data in buffer to NSData. How can i achieve that?
I tried this way:
Byte *buffer = (Byte*)malloc(asset.defaultRepresentation.size);
NSUInteger k = [asset.defaultRepresentation getBytes:buffer fromOffset: 0.0
length:asset.defaultRepresentation.size error:nil];
NSData *adata = NSData *adata = [NSData dataWithBytesNoCopy:buffer
length:j freeWhenDone:YES];
It really works!
As #runeb said the answer is not working properly with large files. You should do something like that:
int bufferSize = 2048;
int offset = 0;
NSString* name=nil;
while(offset<asset.size){
Byte *buffer = (Byte*)malloc(bufferSize);
NSUInteger buffered = [asset getBytes:buffer fromOffset:offset length:bufferSize error:nil];
NSData *data;
data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:NO];
if(!name){
//Creates the file and gives it a unique name
name = [FileUtils saveVideoFromAsset:data];
}
else{
//Append data to the file created...
[FileUtils appendData:data toFile:name];
}
offset+=buffered;
free(buffer);
}
In order to append data to a file you can use that:
NSFileHandle *myHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
[myHandle seekToEndOfFile];
[myHandle writeData:videoData];
I hope that helps!
ust add #autoreleasepool block, so that any autorleased objects should be cleaned up. it looks like that ARC has something changed after iOS7
#autoreleasepool {
NSUInteger readStatus = [rep getBytes:buffer fromOffset:_startFromByte length:chunkSize error:NULL];
}

Any cocoa source code for AES encryption decryption?

I am searching for some cocoa code on AES encryption and I did some google search for it. I found this very useful link -
http://iphonedevelopment.blogspot.com/2009/02/strong-encryption-for-cocoa-cocoa-touch.html. So I tried it but it did not work for me.
Can anyone suggest me some useful link or source code which can help me to implement it in my sample application.
I use a simple category on NSData that uses the built-in CommonCrypto framework to do AES 256-bit encryption. I use this on the Mac but it should work OK on iPhone too:
#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'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
AES128 encryption is available on the iPhone in the CommonCrypto framework. The relevant functions are in the CommonCryptor.h header.
You can create a cryptor like so:
// Assume key and keylength exist
CCCryptorRef cryptor;
if(kCCSuccess != CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, 0, key, keyLength, NULL, &cryptor))
; //handle error
// Repeatedly call CCCryptorUpdate to encrypt the data
CCCryptorRelease(cryptor);
It seems from the question and the link that you are looking for example implementations of AES. I would not recommend this- use Apple's implementation!
It looks like http://pastie.org/297563.txt might help you also, but I haven't tested it.
All examples I found didn't work for me, so I changed the solution above. This one works for me and uses the Google-Lib for Base64 stuff:
+ (NSData *)AES256DecryptWithKey:(NSString *)key data:(NSData*)data encryptOrDecrypt:(CCOperation)encryptOrDecrypt {
// '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];
if (encryptOrDecrypt == kCCDecrypt)
{
data = [GTMBase64 decodeData:data];
}
NSUInteger dataLength = [data 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(encryptOrDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
keyPtr,
kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[data bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus != kCCSuccess){
NSLog(#"ERROR WITH FILE ENCRYPTION / DECRYPTION");
return nil;
}
NSData *result;
if (encryptOrDecrypt == kCCDecrypt)
{
result = [NSData dataWithBytes:(const void *)buffer length:(NSUInteger)numBytesDecrypted];
}
else
{
NSData *myData = [NSData dataWithBytes:(const void *)buffer length:(NSUInteger)numBytesDecrypted];
result = [GTMBase64 encodeData:myData];
}
free(buffer); //free the buffer;
return result;
}
thanks for the great category extension. One thing that I've discovered - when you use CCCrypt with an algorithm stronger then 64 bit, you need to be compliant to the BIS export regulations. See the iTunes Connect FAQ for more details. Even if you use Apple's inbuild crypto api you need to get approval from the BIS.
There was a discussion on sf about this topic before (in context of ssl usage):
Using SSL in an iPhone App - Export Compliance
Best Regards
Chris

Resources