iOS AES Encryption with Vulnerability: Signed Memory Arithmetic - ios

I'm using AES encryption to encrypt / decrypt user's info in my app.
This is the code I'm using:
https://gist.github.com/matsuda/9204276
Everything works just fine.
But the code got scanned for security vulnerability recently and there's an issue that got flagged.
The vulnerability:
Signed Memory Arithmetic
Description:
The software reads or writes to a buffer using an index or pointer that references a memory location after the end of the buffer.
Line 39-40 of NSData+AES.m of the code in the above link is where it got highlighted
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
I'm not sure what I should do.
The buffer size is calculated with dataLength + kCCBlockSizeAES128 just before allocation so the length should be okay?
Thanks for your help in advance.

Related

AES128 Encryption CBC/NoPadding Objective-C

We need to encrypt a request using AES128 in Android and IOS and then send that encrypted message in the backend server written in Java.
Our Android encryption code is like below:
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
where keyspec and ivspec is random bytes generated.
In Objective-C, this is how we do the encryption.
NSString* iv = #"a12bc1256b4de9a0";
NSData* ivData = [iv dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData* cipherData = [NSMutableData dataWithLength:data.length+kCCBlockSizeAES128];
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, keyData.bytes, keyData.length, ivData.bytes, data.bytes, data.length, cipherData.mutableBytes, cipherData
.length, &outLength);
The problem with this is that when we compare the encrypted byte of thee Java program and Objective-C, they are not the same. I understand that the CCOption parameter in Objective-C should be CBC but that is not in the enum list of the CommonCrypto library. When we set it 0, the encrypted byte only return a series of zeros.
Please suggest other alternatives on how to do the AES 128 encryption in Objective-C using AES/CBC/NOPadding Algorithm.
You've requested padding: kCCOptionPKCS7Padding. That's not the same thing as Java's NoPadding. Remove the padding option. (You can use 0 to mean "no options.")
It's also unclear whether every other part of your encryption it the same. You didn't include the key generation or IV in the Java code.
(Note that if you get the exact same bytes out of an encryption algorithm for the same message, then you're using the encryption algorithm in an insecure way. Secure encryption constructions will generate a different cipher text for every encryption. I understand that your server may be using this kind of insecure approach; it's a very common mistake. But it is insecure.)

RSA decryption fails in iOS

I'm trying to do RSA2048 in iOS and am following the example codes from Apple and also this question RSA implementations in Objective C. I have tested on iPhone 5c with iOS 8.4.1, but the sample codes fail at decryption with private key, with error code -9809 (An underlying cryptographic error was encountered), even though encryption with public key. I understand the basic approach is to generate an RSA key pair, secure them in keychain and use public key ref to encrypt and private key to decrypt. I'm completely lost why decryption shall fail, and not always, there are times when decryption succeeded.
Full codes can be found at https://gist.github.com/aceisScope/372e6d6f92650ce03624. The decryption part that throws an error is below, where from time to time status = -9809, and other times it works and returns 0:
status = SecKeyDecrypt(privateKey,
PADDING,
cipherBuffer,
cipherBufferSize,
plainBuffer,
&plainBufferSize
);
I have also set a check that if such key pair has already generated, next time encryption/decryption is called, it will directly using the already-generated-and-stored key pair from key chain without generating a new pair.
Update:
I came across this post iPhone Public-Key Encryption SecKeyEncrypt returns error 9809 (errSSLCrypto) which found out wrong cipher buffer size may cause -9809 error to encryption. Yet even if I make sure both the cipher buffer size in encryption and plain buffer size in decryption is the same as key block size and private key block size, encryption always works but with decryption failing from time to time.
I found the problem. By the end of encryption, when converting cipher buffer to NSData, in the following code
NSMutableData *data=[[NSMutableData alloc] init];
[data appendBytes:cipherBuffer length:strlen( (char*)cipherBuffer ) + 1];
the length is not correct. It should be the size of the cipher buffer, which is the same as key block size.
So after changing it to
NSData *data = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];
decryption works now.

convert uint8_t to NSData

I have implemented publickey privatekey RSA encryption in iOS application based on the examples provided on the Apple Developer site.
It works perfectly if I encrypt and return the uint8_t cipherBuffer, and then decrypt from the uint8_t cipherBuffer. However I need to store the encrypted data to an .xcdata model as NSData.
The problem I'm having is reliably converting the uint8_t cipherBuffer to NSData and/or converting the NSData back to uint8_t when it's time to decrypt. The decrypted data appears to be truncated.
This is how I'm converting the uint8_t encrypted buffer to NSData:
return [NSData dataWithBytesNoCopy:cipherBuffer length:BUFFER_SIZE];
This is how I'm converting the encrypted NSData back to a uint8_t buffer when it is time to decrypt it:
uint8_t *cipherBuffer = (uint8_t*)[cipherText bytes];
Thanks jgh and Jody;
I changed the encryption method to "malloc" the buffer and tried several approaches to write the bytes to NSData, wound up with:
return [NSData dataWithBytes:(const void *)cipherBuffer length:CIPHER_BUFFER_SIZE];
What finally fixed the issue was changing the way I was creating the uint8_t in the decryption method:
const uint8_t *cipherBuffer = (const uint8_t*)[data bytes];
Without seeing how you're creating cipherBuffer, it's difficult to say exactly why it's not working. However, from the documentation on dataWithBytesNoCopy:
The returned object takes ownership of the bytes pointer and frees it on deallocation. Therefore, bytes must point to a memory block allocated with malloc.
If you're just declaring cipherBuffer as
uint8_t cipherBuffer[BUFFER_SIZE];
it may explain your problems. Instead, use malloc:
uint8_t* cipherBuffer = malloc(BUFFER_SIZE);
It sounds like you are giving it a raw pointer, then re-using that pointer.
dataWithBytesNoCopy: wants to keep the pointer you give it. In fact, you must give it a pointer that you created with malloc, because it will free it when it's done with the data.
If you do not want the NSData object to take ownership, you should use dataWithBytesNoCopy:length:freeWhenDone:.

What is the correct way to clear sensitive data from memory in iOS?

I want to clear sensitive data from memory in my iOS app.
In Windows I used to use SecureZeroMemory. Now, in iOS, I use plain old memset, but I'm a little worried the compiler might optimize it:
https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/771-BSI.html
code snippet:
NSData *someSensitiveData;
memset((void *)someSensitiveData.bytes, 0, someSensitiveData.length);
Paraphrasing 771-BSI (link see OP):
A way to avoid having the memset call optimized out by the compiler is to access the buffer again after the memset call in a way that would force the compiler not to optimize the location. This can be achieved by
*(volatile char*)buffer = *(volatile char*)buffer;
after the memset() call.
In fact, you could write a secure_memset() function
void* secure_memset(void *v, int c, size_t n) {
volatile char *p = v;
while (n--) *p++ = c;
return v;
}
(Code taken from 771-BSI. Thanks to Daniel Trebbien for pointing out for a possible defect of the previous code proposal.)
Why does volatile prevent optimization? See https://stackoverflow.com/a/3604588/220060
UPDATE Please also read Sensitive Data In Memory because if you have an adversary on your iOS system, your are already more or less screwed even before he tries to read that memory. In a summary SecureZeroMemory() or secure_memset() do not really help.
The problem is NSData is immutable and you do not have control over what happens. If the buffer is controlled by you, you could use dataWithBytesNoCopy:length: and NSData will act as a wrapper. When finished you could memset your buffer.

Best Place to Store Included AWS Credentials in an iOS Application

I plan on using the AWS SDK for iOS for an upcoming project. I need to store credentials for AWS with the packed application. Where is the most secure place to place them? I know that storing them in a pList would be a bad idea. Is it better to just 'hard-code' it into a class that will be compiled? Is there any risk there?
I believe that completely hiding the credentials is theoretically impossible. That is, if your compiled code can read them, then in theory so can anyone with access to the compiled code. But imperfect security is still worth something. I'd guess that most attackers would just look through the binary for strings that look like secret keys, and not go to the trouble of decompiling the code and trying to interpret how it works, so one way to hide the credentials would be to store them in an encoded form, then decode them as needed. This way the decoding algorithm becomes your key, and an attacker would have to find and understand it to extract your credentials.
Here's a fairly simple way to do it using a random XOR mask. Replace the following bogus password with yours, and remember to keep the NULL terminator (\0) in place. Compile and run this code as a standalone program:
#include <stdio.h>
#define PAD_LENGTH 32
int main() {
int i;
char c;
// start with the password
char password[PAD_LENGTH] = "My AWS Password\0";
// make a random pad to encrypt it
printf("PAD:\n{");
char pad[PAD_LENGTH];
for (i = 0; i < PAD_LENGTH; i++) {
c = arc4random() & 0xFF;
pad[i] = c;
printf("%#02x", c & 0xFF);
if (i < PAD_LENGTH - 1) printf(",");
}
printf("}\n");
// make an encrypted version of the password
printf("KEY:\n{");
for (i = 0; i < PAD_LENGTH; i++) {
c = pad[i] ^ password[i];
printf("%#02x", c & 0xFF);
if (i < PAD_LENGTH - 1) printf(",");
}
printf("}\n");
return(0);
}
Then copy the generated pad and key into code like this (which will actually get included with your app):
#define PAD_LENGTH 32
char pad[PAD_LENGTH] = {0x83,0x26,0x8a,0x8b,0xee,0xab,0x6,0xed,0x2e,0x99,0xff,0x23,0x7f,0xef,0xc8,0x8,0x6b,0x8e,0xa4,0x64,0x6d,0xb,0x7,0xd2,0x6a,0x39,0x60,0xa4,0xa9,0xad,0xea,0xb8};
char key[PAD_LENGTH] = {0xce,0x5f,0xaa,0xca,0xb9,0xf8,0x26,0xbd,0x4f,0xea,0x8c,0x54,0x10,0x9d,0xac,0x8,0x6b,0x8e,0xa4,0x64,0x6d,0xb,0x7,0xd2,0x6a,0x39,0x60,0xa4,0xa9,0xad,0xea,0xb8};
for (int i = 0; i < PAD_LENGTH; i++) {
key[i] = key[i] ^ pad[i];
}
NSString *password = [NSString stringWithCString:key encoding:NSASCIIStringEncoding];
Since this is on a public forum, you might want to change a few things, like making the pads a different length, splitting them up and rejoining them with code, reordering them, etc. You could also store the pad and key in distant parts of the code. A truly skilled and dedicated attacker is going to be able to find your password no matter what, but the basic idea is that most people scanning the binary for a password will not find it as such.
Have you looked at the Data Protection API?
What are the new "iOS data protection APIs"?
There are various options depending on your security needs.
This question may help also.
Data Protection on iOS
The video from a conference this year was useful.
http://developer.apple.com/videos/wwdc/2010
you should use AWS Identity and Access Management (IAM): http://aws.amazon.com/iam/
you can find more information about AWS Credential Management in Mobile Applications on http://aws.amazon.com/articles/4611615499399490

Resources