I am trying to use CommonCrypto to encrypt an NSMutableData object in place (copying the resulting bytes to itself, without duplicating it). Previously, I was using CCCrypt() "one-shot" method, mainly because it seemed simple. I noticed that my data object got duplicated in memory.
To avoid this, I tried using an NSInputStream object with a buffer size of 2048 bytes. I am reading my NSMutableData object, and continuously call CCCryptorUpdate(), to handle the encryption. The problem is, that it still seems to be duplicated. Here's my current code (please note that it's a category on NSMutableData - mainly because of historical reasons - thus the "self" references):
- (BOOL)encryptWithKey:(NSString *)key
{
// Key creation - not relevant to the dercribed problem
char * keyPtr = calloc(1, kCCKeySizeAES256+1);
[key getCString: keyPtr maxLength: sizeof(keyPtr) encoding: NSUTF8StringEncoding];
// Create cryptographic context for encryption
CCCryptorRef cryptor;
CCCryptorStatus status = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode, keyPtr, kCCKeySizeAES256, NULL, &cryptor);
if (status != kCCSuccess)
{
MCLog(#"Failed to create a cryptographic context (%d CCCryptorStatus status).", status);
}
// Initialize the input stream
NSInputStream *inStream = [[NSInputStream alloc] initWithData:self];
[inStream open];
NSInteger result;
// BUFFER_LEN is a define 2048
uint8_t buffer[BUFFER_LEN];
size_t bytesWritten;
while ([inStream hasBytesAvailable])
{
result = [inStream read:buffer maxLength:BUFFER_LEN];
if (result > 0)
{
// Encryption goes here
status = CCCryptorUpdate(
cryptor, // Previously created cryptographic context
&result, // Input data
BUFFER_LEN, // Length of the input data
[self mutableBytes], // Result is written here
[self length], // Size of result
&bytesWritten // Number of bytes written
);
if (status != kCCSuccess)
{
MCLog(#"Error during data encryption (%d CCCryptorStatus status)", status);
}
}
else
{
// Error
}
}
// Cleanup
[inStream close];
CCCryptorRelease(cryptor);
free(keyPtr);
return ( status == kCCSuccess );
}
I am definitely missing something obvious here, encryption, and even using input streams is a bit new to me..
As long as you only call CCUpdate() one time, you can encrypt into the same buffer you read from without using a stream. See RNCryptManager.m for an example. Study applyOperation:fromStream:toStream:password:error:. I did use streams here, but there's no requirement that you do that if you already have an NSData.
You must ensure that CCUpdate() is only called one time, however. If you call it multiple times it will corrupt its own buffer. This is an open bug in CommonCryptor (radar://9930555).
As a side note: your key generation is extremely insecure, and use of ECB mode for this kind of data barely qualifies as encryption. It leaves patterns in the ciphertext which can be used to decrypt the data, in some cases just by looking at it. I do not recommend this approach if you actually intend to secure this data. If you want to study how to use these tools well, see Properly Encrypting With AES With CommonCrypto. If you want a prepackaged solution, see RNCryptor. (RNCryptor does not currently have a convenient method for encrypting in-place, however.)
In the line:
result = [inStream read:buffer maxLength:BUFFER_LEN];
the data is read into buffer and result is set to the outcome of the execution.
in lines:
status = CCCryptorUpdate(cryptor, &result, ...
You should be using buffer for the input data, not the status
status = CCCryptorUpdate(cryptor, buffer, ...
Using better names would help eliminate the simple error. If instead of result the variable had been named readStatus the error would most likely not occurred. Likewise instead of naming rthe data variable buffer it had been named streamData things would also have been more clear. Poor naming really can cause errors.
Related
Right now I'm investigating possibility to implement video streaming through MultipeerConnectivity framework. For that purpose I'm using NSInputStream and NSOutputStream.
The problem is: I can't receive any picture so far. Right now I'm trying to pass simple picture and show it on the receiver. Here's a little snippet of my code:
Sending picture via NSOutputStream:
- (void)sendMessageToStream
{
NSData *imgData = UIImagePNGRepresentation(_testImage);
int img_length = (int)[imgData length];
NSMutableData *msgData = [[NSMutableData alloc] initWithBytes:&img_length length:sizeof(img_length)];
[msgData appendData:imgData];
int msg_length = (int)[msgData length];
uint8_t *readBytes = (uint8_t *)[msgData bytes];
uint8_t buf[msg_length];
(void)memcpy(buf, readBytes, msg_length);
int stream_len = [_stream writeData:(uint8_t*)buf maxLength:msg_length];
//int stream_len = [_stream writeData:(uint8_t *)buf maxLength:data_length];
//NSLog(#"stream_len = %d", stream_len);
_tmpCounter++;
dispatch_async(dispatch_get_main_queue(), ^{
_lblOperationsCounter.text = [NSString stringWithFormat:#"Sent: %ld", (long)_tmpCounter];
});
}
The code above works totally fine. stream_len parameter after writing equals to 29627 bytes which is expected value, because image's size is around 25-26 kb.
Receiving picture via NSinputStream:
- (void)readDataFromStream
{
UInt32 length;
if (_currentFrameSize == 0) {
uint8_t frameSize[4];
length = [_stream readData:frameSize maxLength:sizeof(int)];
unsigned int b = frameSize[3];
b <<= 8;
b |= frameSize[2];
b <<= 8;
b |= frameSize[1];
b <<= 8;
b |= frameSize[0];
_currentFrameSize = b;
}
uint8_t bytes[1024];
length = [_stream readData:bytes maxLength:1024];
[_frameData appendBytes:bytes length:length];
if ([_frameData length] >= _currentFrameSize) {
UIImage *img = [UIImage imageWithData:_frameData];
NSLog(#"SETUP IMAGE!");
_imgView.image = img;
_currentFrameSize = 0;
[_frameData setLength:0];
}
_tmpCounter++;
dispatch_async(dispatch_get_main_queue(), ^{
_lblOperationsCounter.text = [NSString stringWithFormat:#"Received: %ld", (long)_tmpCounter];
});
}
As you can see I'm trying to receive picture in several steps, and here's why. When I'm trying to read data from stream, it's always reading maximum 1095 bytes no matter what number I put in maxLength: parameter. But when I send the picture in the first snippet of code, it's sending absolutely ok (29627 bytes . Btw, image's size is around 29 kb.
That's the place where my question come up - why is that? Why is sending 29 kb via NSOutputStream works totally fine when receiving is causing problems? And is there a solid way to make video streaming work through NSInputStream and NSOutputStream? I just didn't find much information about this technology, all I found were some simple things which I knew already.
Here's an app I wrote that shows you how:
https://app.box.com/s/94dcm9qjk8giuar08305qspdbe0pc784
Build the project with Xcode 9 and run the app on two iOS 11 devices.
To stream live video, touch the Camera icon on one of two devices.
If you don't have two devices, you can run one app in the Simulator; however, you can only use the camera on the real device (the Simulator will display the video broadcasted).
Just so you know: this is not the ideal way to stream real-time video between devices (it should probably be your last choice). Data packets (versus streaming) are way more efficient and faster.
Regardless, I'm really confused by your NSInputStream-related code. Here's something that makes a little more sense, I think:
case NSStreamEventHasBytesAvailable: {
// len is a global variable set to a non-zero value;
// mdata is a NSMutableData object that is reset when a new input
// stream is created.
// displayImage is a block that accepts the image data and a reference
// to the layer on which the image will be rendered
uint8_t * buf[len];
len = [aStream read:(uint8_t *)buf maxLength:len];
if (len > 0) {
[mdata appendBytes:(const void *)buf length:len];
} else {
displayImage(mdata, wLayer);
}
break;
}
The output stream code should look something like this:
// data is an NSData object that contains the image data from the video
// camera;
// len is a global variable set to a non-zero value
// byteIndex is a global variable set to zero each time a new output
// stream is created
if (data.length > 0 && len >= 0 && (byteIndex <= data.length)) {
len = (data.length - byteIndex) < DATA_LENGTH ? (data.length - byteIndex) : DATA_LENGTH;
uint8_t * bytes[len];
[data getBytes:&bytes range:NSMakeRange(byteIndex, len)];
byteIndex += [oStream write:(const uint8_t *)bytes maxLength:len];
}
There's a lot more to streaming video than setting up the NSStream classes correctly—a lot more. You'll notice in my app, I created a cache for the input and output streams. This solved a myriad of issues that you would likely encounter if you don't do the same.
I have never seen anyone successfully use NSStreams for video streaming...ever. It's highly complex, for one reason.
There are many different (and better) ways to stream video; I wouldn't go this route. I just took it on because no one else has been able to do it successfully.
I think that the problem is in your assumption that all data will be available in NSInputStream all the time while you are reading it. NSInputStream made from NSURL object has an asynchronous nature and it should be accessed accordingly using NSStreamDelegate. You can look at example in the README of POSInputStreamLibrary.
I've been working on this for a long time, but am stuck.
I'm writing an iOS app that takes AES encrypted data form a Go server-side application and decrypts it. I'm using CCCryptor for the decryption on the iOS side. However, I cannot, for the life of me, get plaintext out. There is a working Java/Android implementation, and it decrypts fine on the Go side, so I'm pretty sure it's to do with my CCCryptor settings.
I'm actually getting a 0 success status on decryption, but taking the output and doing a NSString initWithBytes gives me a null string.
Note: I'm only writing the iOS side.
Go code that encrypts:
func encrypt(key, text []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
b := encodeBase64(text)
ciphertext := make([]byte, aes.BlockSize+len(b))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
cfb := cipher.NewCFBEncrypter(block, iv)
cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
return ciphertext
}
Objective-C code that decrypts
+ (NSData *)decrypt:(NSData*)data withPassword:(NSString*)password{
NSData * key = [password dataUsingEncoding:NSUTF8StringEncoding];
size_t dataLength = [data length] - kCCBlockSizeAES128;
NSData *iv = [data subdataWithRange:NSMakeRange(0, kCCBlockSizeAES128)];
NSData *encrypted = [data subdataWithRange:NSMakeRange(kCCBlockSizeAES128, dataLength)];
//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(dataLength);
NSMutableData *ret = [NSMutableData dataWithLength:dataLength + kCCBlockSizeAES128];
size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
0x0000, // change to 0 solve the problem
[key bytes],
kCCKeySizeAES256,
[iv bytes],
[encrypted bytes], dataLength, /* input */
[ret mutableBytes], [ret length], /* output */
&numBytesDecrypted
);
NSLog(#"err: %d", status);
NSLog(#"dataLength: %d, num: %d", (int)dataLength, (int)numBytesDecrypted);
if (status == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return ret;
}
// free(buffer); //free the buffer;
return nil;
}
My recommendation is to use RNCryptor, there is an iOS and a Go implementation available.
RNCryptor combines all the necessary cryptographic primitives for your needs including:
AES-256 encryption (Advanced Encryption Standard)
CBC mode (Cipher Block Chaining)
Password stretching with PBKDF2 (Password Based Key Derivation Function 2)
Password salting
Random IV (Initialization Vector)
Encrypt-then-hash HMAC (Authentication)
It has been extensively deployed and vetted.
It is all to easy to get cryptography wrong and using RNCryptor will avoid the potential pitfalls.
If I had the cryptographic needs you have I would use it.
I'm not sure how secure is my solution.
Rob Napier has an extraordinary Framework (RNCryptor) to encrypt and decrypt in iOS and other systems.
As far as I know, he is using AES-CBC, that in fact is the standard of CommonCryptor.h
However, my requirements, has forced me to use AES-CTR. Both are really similar, so in theory it had to be something easy. But was not.
There is a lack of information around CommonCryptor.h. It is one of the worst explained frameworks ever.
Working with CBC you just need to call CCCrypt(). However, to work with CTR you should call: CCCrytorCreate(), CCCryptorUpdate(), CCCryptorFinal() and CCCryptorRelease()
Trying to encrypt my data, I was receiving different data every time, of course decrypting it had incorrect results.
I had 2 big problems in my first approach: the length of the key and the number of bytes written to dataOut.
I sorted the problems with:
1.- A NSString key of 32 characters
NSString *key = #"1234567890ABCDEFGHIJKLMNOPQRSTUV";
2.- To cut dataOut with needed length
Finally this is my code to Encrypt and Decrypt:
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonKeyDerivation.h>
#import <Security/Security.h>
+ (NSMutableData*) encryptString: (NSString*) stringToEncrypt withKey: (NSString*) keyString
{
//Key to Data
NSData *key = [keyString dataUsingEncoding:NSUTF8StringEncoding];
//String to encrypt to Data
NSData *data = [stringToEncrypt dataUsingEncoding:NSUTF8StringEncoding];
// Init cryptor
CCCryptorRef cryptor = NULL;
// Alloc Data Out
NSMutableData *cipherData = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];
//Empty IV: initialization vector
NSMutableData *iv = [NSMutableData dataWithLength:kCCBlockSizeAES128];
//Create Cryptor
CCCryptorStatus create = CCCryptorCreateWithMode(kCCEncrypt,
kCCModeCTR,
kCCAlgorithmAES,
ccPKCS7Padding,
iv.bytes, // can be NULL, because null is full of zeros
key.bytes,
key.length,
NULL,
0,
0,
kCCModeOptionCTR_BE,
&cryptor);
if (create == kCCSuccess)
{
//alloc number of bytes written to data Out
size_t outLength;
//Update Cryptor
CCCryptorStatus update = CCCryptorUpdate(cryptor,
data.bytes,
data.length,
cipherData.mutableBytes,
cipherData.length,
&outLength);
if (update == kCCSuccess)
{
//Cut Data Out with nedded length
cipherData.length = outLength;
//Final Cryptor
CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
cipherData.mutableBytes, //void *dataOut,
cipherData.length, // size_t dataOutAvailable,
&outLength); // size_t *dataOutMoved)
if (final == kCCSuccess)
{
//Release Cryptor
//CCCryptorStatus release =
CCCryptorRelease(cryptor ); //CCCryptorRef cryptorRef
}
return cipherData;
}
}
else
{
//error
}
return nil;
}
+ (NSString*) decryptData: (NSData*) data withKey: (NSString*) keyString
{
//Key to Data
NSData *key = [keyString dataUsingEncoding:NSUTF8StringEncoding];
// Init cryptor
CCCryptorRef cryptor = NULL;
//Empty IV: initialization vector
NSMutableData *iv = [NSMutableData dataWithLength:kCCBlockSizeAES128];
// Create Cryptor
CCCryptorStatus createDecrypt = CCCryptorCreateWithMode(kCCDecrypt, // operation
kCCModeCTR, // mode CTR
kCCAlgorithmAES, // Algorithm
ccPKCS7Padding, // padding
iv.bytes, // can be NULL, because null is full of zeros
key.bytes, // key
key.length, // keylength
NULL, //const void *tweak
0, //size_t tweakLength,
0, //int numRounds,
kCCModeOptionCTR_BE, //CCModeOptions options,
&cryptor); //CCCryptorRef *cryptorRef
if (createDecrypt == kCCSuccess)
{
// Alloc Data Out
NSMutableData *cipherDataDecrypt = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];
//alloc number of bytes written to data Out
size_t outLengthDecrypt;
//Update Cryptor
CCCryptorStatus updateDecrypt = CCCryptorUpdate(cryptor,
data.bytes, //const void *dataIn,
data.length, //size_t dataInLength,
cipherDataDecrypt.mutableBytes, //void *dataOut,
cipherDataDecrypt.length, // size_t dataOutAvailable,
&outLengthDecrypt); // size_t *dataOutMoved)
if (updateDecrypt == kCCSuccess)
{
//Cut Data Out with nedded length
cipherDataDecrypt.length = outLengthDecrypt;
// Data to String
NSString* cipherFinalDecrypt = [[NSString alloc] initWithData:cipherDataDecrypt encoding:NSUTF8StringEncoding];
//Final Cryptor
CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
cipherDataDecrypt.mutableBytes, //void *dataOut,
cipherDataDecrypt.length, // size_t dataOutAvailable,
&outLengthDecrypt); // size_t *dataOutMoved)
if (final == kCCSuccess)
{
//Release Cryptor
//CCCryptorStatus release =
CCCryptorRelease(cryptor); //CCCryptorRef cryptorRef
}
return cipherFinalDecrypt;
}
}
else
{
//error
}
return nil;
}
To call it:
NSString *key = #"1234567890ABCDEFGHIJKLMNOPQRSTUV";
NSString *stringToEncrypt = #"Gabriel.Massana";
NSData* encrypted = [GM_AES128_CTR encryptString:stringToEncrypt withKey:key];
NSString *decrypted = [GM_AES128_CTR decryptData:encrypted withKey:key];
I'm posting my solution because there are not to much questions for AES CTR in Stackoverflow. Likewise, if someone want to check it and tell me if something is wrong will be very appreciated.
My example in GitHub
How secure is this solution? It is easy to crack the system? What are my possibilities to add more security to AES-CTR?
I'm listing this as a separate answer, but I'm just amplifying what Zaph has already said:
This is totally broken encryption.
It's not surprising that this has happened to you. It is a very common problem when you try to build your own scheme. There are just a lot of places you can mess up. But I don't want to understate just how insecure this scheme is. It is really, really broken.
CTR cannot ever repeat the same nonce+key, and you reuse the nonce every time. This is very different from CBC. In CBC if you reuse the IV, then you make it somewhat easier on the attacker to break your encryption. In CTR, if you reuse the nonce+key it is pretty easy to decrypt the message once you have a few ciphertexts. Some good discussion can be found in RFC3686.
When used correctly, AES-CTR provides a high level of
confidentiality. Unfortunately, AES-CTR is easy to use incorrectly.
Being a stream cipher, any reuse of the per-packet value, called the
IV, with the same nonce and key is catastrophic. An IV collision
immediately leaks information about the plaintext in both packets.
For this reason, it is inappropriate to use this mode of operation
with static keys. Extraordinary measures would be needed to prevent
reuse of an IV value with the static key across power cycles. To be
safe, implementations MUST use fresh keys with AES-CTR. The Internet
Key Exchange (IKE) [IKE] protocol can be used to establish fresh
keys. IKE can also provide the nonce value.
Note that RNCryptor originally used CTR. I moved back to CBC on the recommendation of Apple after talking with them about how hard easy it is to screw up CTR. If you can avoid CTR, you absolutely should. It is extremely useful for certain problems, but for general file encryption it is seldom appropriate.
That said, I understand you have a problem in the chip. How is your chip going to get its key? It seems strange to use symmetric encryption with a chip this way. In any case, RNCryptor v1 may meet your needs. You'd likely need to use encryptFromStream:toStream:encryptionKey:HMACKey:error: since I assume the chip can't handle PBKDF2.
Trying to encrypt my data, I was receiving different data every time, of course decrypting it had incorrect results.
Any good encryption system will have this property. That's why you need to send your nonce/IV (and if you use passwords, salts) along with the ciphertext.
NSString *key = #"1234567890ABCDEFGHIJKLMNOPQRSTUV";
This is not a key. This is a password and dramatically reduces your available keyspace. Keys are typically going to be NSData since they need to be chosen over all possible values, not just ASCII.
On an iPhone, with ios 6.1.3, I'm trying to write to an outputStream, without an NSRunLoop. My stream is simply initialized by:
session = [[EASession alloc] initWithAccessory:accessory
forProtocol:protocolString];
if (session)
{
NSLog(#"opening the streams for this accessory");
[[session inputStream] open];
[[session outputStream] open];
[session retain];
streamReady = true;
receivedAccPkt = true;
}
Then, elsewhere in the code, when I try to transmit data as follows:
uint8_t requestData[8] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8};
while (![[eas outputStream] hasSpaceAvailable]);
#synchronized(self) {
len += [[eas outputStream] write:requestData maxLength:8];
}
The 'hasSpaceAvailable' method never returns true, so the code is stuck.
Are there any other initialisation tasks to be done for an output stream, in order to send data?
The EASession documentation states that you need to configure the streams by assigning it a delegate which handles the stream events and schedule it in a run loop.
Using a run loop enables you to drive the streams without worrying about threads. For example, if you write into the output stream via the outputStream property, there's very likely an internal input stream (bound to the public visible output stream) which is used by the EASession object to obtain the bytes written. This internal input stream (which is not visible) may also use the same run loop as the publicly provided output stream outputStream.
Don't mismatch the internal input stream with the public input stream! So basically, there are two public streams and two internal streams. Each public stream has an associated pendant internally: a input stream has a bound output stream, and an output stream has a bound input stream.
You can however, avoid using a run loop for your (output) stream: you just need to guarantee that the write:maxLength: method is executed on a private thread, which is not used by the internal streams by EASession.
You can get your private thread just by utilizing dispatch. You may try the code below:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[outputStream open];
const char* data = ...;
int dataLength = ...;
while (dataLength && !isCancelled) {
int written = [outputStream write:(const uint8_t*)data maxLength:1];
if (written > 0) {
dataLength -= written;
data += written;
}
else if (written < 0 )
{
// error occurred
break;
}
}
[outputStream close];
});
Note: this will block the thread if a previous call to write:maxLength: returned zero and if there is still data to write. Thus, the internal streams must not use the same thread, otherwise you get a dead lock.
When the thread is blocked, it becomes difficult to cancel the block. Perhaps, you should try a run loop approach.
I have some problems decrypting a file encrypted with openssl in a bash. Below is what I did step by step. I can't figure out where does it go wrong.
The original file (ended with newline) :
123456
abcdef
ghijkl
Generate 32 bytes long random password :
$ openssl rand -hex 32
fec8950708098e9075e8b4df9a969aa7963c4d820158e965c7848dbfc8ca73ed
Encrypt the file :
$ openssl aes-128-ecb -in original.txt -out encrypted.txt
About the encrypted file :
$ file encrypted.txt
encrypted.txt: Non-ISO extended-ASCII text, with CR line terminators, with overstriking
$ cat encrypted.txt
Salted__??\z?F?z????4G}Q? Y?{ӌ???????b*??
Code to call the decrypt method :
NSData *myDataDec = [self aesDecrypt:#"fec8950708098e9075e8b4df9a969aa7963c4d820158e965c7848dbfc8ca73ed" data:myData];
NSLog(#"decrypted: %#", [[NSString alloc] initWithData:myDataDec encoding:NSASCIIStringEncoding]);
Method to decrypt :
- (NSData *)aesDecrypt:(NSString *)key data:(NSData *)data
{
// '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 = [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 numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
keyPtr,
kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[data bytes],
dataLength, /* input */
buffer,
bufferSize, /* output */
&numBytesEncrypted);
NSLog(#"cryptStatus: %d", cryptStatus);
if (cryptStatus == kCCSuccess)
{
NSLog(#"aes success");
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
NSLog(#"aes error");
free(buffer); //free the buffer;
return nil;
}
Logs :
2012-09-01 15:08:51.331 My Project[75582:f803] cryptStatus: -4304
2012-09-01 15:08:51.332 My Project[75582:f803] aes error
2012-09-01 15:08:51.332 My Project[75582:f803] decrypted:
kCCDecodeError details :
kCCDecodeError - Input data did not decode or decrypt properly.
OpenSSL uses a nonstandard format. AESencrypt is very broken (and insecure). Put them together and it's not going to work. See RNCryptor for an OpenSSL-compatible solution on iOS. OpenSSL has a lot of problems itself, but it's the best commandline option I can recommend right now.
You do not appear to be adding padding when encrypting the file. You appear to be expecting PKCS7 padding when decrypting. The decryption method will automatically check for the correct padding. If it finds incorrect padding, then it will throw an error.
Add PKCS7 padding to your encryption method and see what happens.
Also note that ECB is not a secure mode. Use CBC or CTR modes for preference. Use GCM mode if you require authentication as well as encryption.