How to fix Veracode Use After Free (CWE ID 416)
Recommendations from Veracode: Ensure that all pointers are set to NULL once the memory they point to has been freed.
Error pointed on: Line 8 "return result;"
+ (NSData *)dataFromBase64String:(NSString *)aString
{
NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding];
size_t outputLength = 0;
void *outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength);
NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength];
free(outputBuffer);
return result;
}
Veracode scan does just help you to find places in code where you could improve security related coding. It does not stop attacks of course, but if your application is really that much security oriented you can make it more difficult to read out memory that is left after processing.
The word "Error" in the logging of Veracode is maybe a bit overused..
But my suggestion to address Veracodes Error pointed on: Line 8 "return result;" would be..
+ (NSData *)dataFromBase64String:(NSString *)aString
{
if (aString!=nil && [aString length]) {
size_t outputLength = 0;
void *outputBuffer = NULL;
NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding];
outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength);
if (outputBuffer==NULL) return nil; //if NewBase64Decode() failed there is nothing to free..
NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength];
free(outputBuffer);
outputBuffer = NULL;
return result;
}
return nil;
}
This is because free'd memory is not set to NULL without your intent, so someone scanning memory for left overs would maybe find some clues about the former content of address.
here some nice discussion if NULL after free is really needed.
If you go that much into detail to avoid any kind of risk then you could also initiate outputBuffer with NULL (void* outputBuffer = NULL;) before you even use it.
Well it is another discussion if this is a bit overdo for some objC code where just swizzling could override the whole method.
EDIT: even more spagetti code, trying to avoid returning any value other than void and change a passed argument instead.
+ (void)dataFromBase64String:(NSString *)aString toResult:(NSData**)result
{
if (aString!=nil && [aString length]) {
size_t outputLength = 0;
void *outputBuffer = NULL;
NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding];
outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength);
if (outputBuffer==NULL) return; //if NewBase64Decode() failed there is nothing to do
*result = [NSData dataWithBytes:outputBuffer length:outputLength];
free(outputBuffer);
outputBuffer = NULL;
}
}
//and call like..
NSData *myresult = nil;
[YOURCLASS dataFromBase64String:#"someString" toResult:&myresult];
NSLog(#"result=%#",myresult);
Now i wonder what Veracode is reporting with the edit above..
Related
I am working on an encryption method in the iPhone with the RSA encryption method, so far i could achieve getting the encryption string with this method, the string is successfully decrypted by the server.
SecKeyRef keyRef = [self addPublicKey:pubKey];
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA256;
if (!keyRef) {
return nil;
}
BOOL canEncrypt = SecKeyIsAlgorithmSupported(keyRef, kSecKeyOperationTypeEncrypt, algorithm);
if (canEncrypt) {
CFErrorRef error = NULL;
NSData *encryptedData = (NSData *)CFBridgingRelease(
SecKeyCreateEncryptedData(keyRef, algorithm, (__bridge CFDataRef) content, &error)
);
if (encryptedData) {
return encryptedData;
}else{
NSError *err = CFBridgingRelease(error);
NSLog(#"Ocurrió un error %#", err.localizedDescription);
return nil;
}
}
This method works for ios 10 and newer, what i need is to know how to set the algorithm in prior ios versions, my code is the following
SecKeyRef keyRef = [self addPublicKey:pubKey];
if (!keyRef) {
return nil;
}
size_t cipherBufferSize = SecKeyGetBlockSize(keyRef);
uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
memset((void *)cipherBuffer, 0*0, cipherBufferSize);
NSData *plainTextBytes = content;
size_t blockSize = cipherBufferSize - 11;
size_t blockCount = (size_t)ceil([plainTextBytes length] / (double)blockSize);
NSMutableData *encryptedData = [NSMutableData dataWithCapacity:0];
for (int i=0; i<blockCount; i++) {
int bufferSize = (int)MIN(blockSize,[plainTextBytes length] - i * blockSize);
NSData *buffer = [plainTextBytes subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];
OSStatus status = SecKeyEncrypt(keyRef,
kSecPaddingOAEP,
(const uint8_t *)[buffer bytes],
[buffer length],
cipherBuffer,
&cipherBufferSize);
if (status == noErr){
NSData *encryptedBytes = [NSData dataWithBytes:(const void *)cipherBuffer length:cipherBufferSize];
[encryptedData appendData:encryptedBytes];
}else{
if (cipherBuffer) {
free(cipherBuffer);
}
return nil;
}
}
if (cipherBuffer) free(cipherBuffer);
So far i can see that in the version of ios 10 you can set the algorithm with this line
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA256;
my question is, how do i get that algorithm in the early version of ios, the second code i post can't be decrypted.
Thanks for your help
If you are using OAEP padding with SecKeyEncrypt, you can only use kSecPaddingOAEP, which is SHA1. Unfortunately you cannot use OAEP SHA256 with SecKeyEncrypt.
I'm facing a problem of password encryption. I'm using AES128 to encrypt the data. Here is the following code:
LoginController.m
#import <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonKeyDerivation.h>
#import "NSData+AES.h"
- (IBAction)loginButtonClick:(id)sender
{
NSData *toencrypt = [password.text dataUsingEncoding:NSUTF8StringEncoding];
NSString *credentials = [self md5:[NSString stringWithFormat:#"63jhdf83hf73haf3983f"]]; //returns 679fb1ddf7d81bee0aff2ef251fe6bf5
NSString *iv = #"kdf67398DF7383fd";
NSData *data = [toencrypt AES128EncryptWithKey:credentials iv:iv];
NSString *postdata = [data base64Encoding]; //base64Encoding is implemented in NSData+AES.m
NSLog(#"Original Password: %#",password);
NSLog(#"Encrypted Password: %#",postdata);
}
**N.B: md5 conversion and base64Encoding is working fine.
NSData+AES.m
static char encodingTable[64] =
{
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
};
#implementation NSData (AES)
- (NSData *)AES128EncryptWithKey:(NSString *)key iv:(NSString *)iv
{
char keyPtr[kCCKeySizeAES128+1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
char ivPtr[kCCKeySizeAES128+1];
bzero(ivPtr, sizeof(ivPtr));
[iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
int newSize = 0;
if(diff > 0){
newSize = (int)dataLength + diff;
}
char dataPtr[newSize];
memcpy(dataPtr, [self bytes], [self length]);
for(int i = 0; i < diff; i++){
dataPtr[i + dataLength] = 0x00;
}
size_t bufferSize = newSize + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
0x00, //No padding
keyPtr,
kCCKeySizeAES128,
ivPtr,
dataPtr,
sizeof(dataPtr),
buffer,
bufferSize,
&numBytesEncrypted);
if(cryptStatus == kCCSuccess)
{
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
return nil;
}
Now If a send "brad" it should return "ur/bq4Rz". But unfortunately it returning "83+eQZW3eI4UWGdNk4nnUw==". Whats the problem? Please help me out. Thanks in advance.
Note that this code is pretty insecure. It reuses the same Key+IV for every message, which greatly simplifies the job of decrypting the message for an attacker (especially short messages). And it has other security problems (poor keyspace, bad padding scheme)
That said, the piece that is specifically broken is that you're passing a 32-byte (256-bit) "key" but you're only using 128-bits of it. You probably meant to use kCCKeySizeAES256 as the key length. This is unrelated to kCCAlgorithmAES128 which refers to the block size, not the key length. In the diff code, you meant to use kCCBlockSizeAES128 rather than kCCKeySizeAES128, but they are both 16 so it doesn't impact the result.
As #Codo notes, standard CBC mode cannot output cipher text that is not a multiple of 16 bytes in length. Why do you believe "ur/bq4Rz" is the correct encryption? There is a modification of CBC that can do this (it adds what is called "cipher text stealing" or CTS), but this isn't supported by iOS.
Your code is doing zero-padding, which is a very poor way to do it (you're just adding zeros until you get to a 16-byte boundary). The standard (and more secure) solution is PKCS#7 padding, which you're turning off.
If I had to guess, you're copying code that zero-pads the data and then truncates the cipher text to length. The decryption then probably pads the cipher text with zeros and then truncates the garbage at the end (probably based on knowing the length beforehand). I see how this can work, but it's not the normal approach.
If you want an example of how to do this simply, see Properly Encrypting With AES and CommonCrypto. If you want a more secure approach that does all of it for you, see RNCryptor. Neither of these will generate cipher text that is the same length as your plaintext, however.
I found some issues, for example you don't check if getCString:maxLength:endocind failed or not. This is deprecated function and it may fail here, as a result encryption method may use completly different key and IV
Here is my version of this method. This should do the job right:
- (NSData *)AES128EncryptWithKey:(NSString *)key iv:(NSString *)iv
{
int diff = kCCKeySizeAES128 - (self.length % kCCKeySizeAES128);
NSMutableData *adjustedData = [NSMutableData dataWithData:self];
[adjustedData appendData:[[NSMutableData alloc] initWithLength:diff]];
size_t bufferSize = adjustedData.length + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
0x00, //No padding
[key UTF8String], kCCKeySizeAES128,
[iv UTF8String],
adjustedData.bytes,
adjustedData.length,
buffer,
bufferSize,
&numBytesEncrypted);
if(cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
return nil;
}
I am struggling (getting memory errors, or apparently not correctly deallocating memory) trying to create a CMBlockBufferRef filled with data from an existing NSData (or NSMutableData).
I would be happy with a solution that copies data, but ideally I would be looking at a solution that would use the underlying NSData bytes and keep a strong reference to the NSData object until the CMBlockBuffer is deallocated.
Only for a read-only buffer referring a NSData (of course, without copying), I've just found a way to achieve it.
static void releaseNSData(void *o, void *block, size_t size)
{
NSData *data = (__bridge_transfer NSData*) o;
data = nil; // Assuming ARC is enabled
}
OSStatus createReadonlyBlockBuffer(CMBlockBufferRef *result, NSData *data)
{
CMBlockBufferCustomBlockSource blockSource =
{
.version = kCMBlockBufferCustomBlockSourceVersion,
.AllocateBlock = NULL,
.FreeBlock = &releaseNSData,
.refCon = (__bridge_retained void*) data,
};
return CMBlockBufferCreateWithMemoryBlock(NULL, (uint8_t*) data.bytes, data.length, NULL, &blockSource, 0, data.length, 0, result);
}
I have one quick question...
I am building a social media network site app and I need to hash the password NSString. How would I accomplish this? I have the password field on the app and would like to hash the string and encode it in SHA512 for the POST request.
Thanks in advance,
TechnologyGuy
Already answered: hash a password string using SHA512 like C#
But here's the copy-pasted code:
#include <CommonCrypto/CommonDigest.h>
+ (NSString *) createSHA512:(NSString *)source {
const char *s = [source cStringUsingEncoding:NSASCIIStringEncoding];
NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
uint8_t digest[CC_SHA512_DIGEST_LENGTH] = {0};
CC_SHA512(keyData.bytes, keyData.length, digest);
NSData *out = [NSData dataWithBytes:digest length:CC_SHA512_DIGEST_LENGTH];
return [out description];
}
Or if you prefer a hashed output, try this:
+(NSString *)createSHA512:(NSString *)string
{
const char *cstr = [string cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:string.length];
uint8_t digest[CC_SHA512_DIGEST_LENGTH];
CC_SHA512(data.bytes, data.length, digest);
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA512_DIGEST_LENGTH; i++)
[output appendFormat:#"%02x", digest[i]];
return output;
}
+ (NSData *)sha512:(NSData *)data {
unsigned char hash[CC_SHA512_DIGEST_LENGTH];
if ( CC_SHA512([data bytes], [data length], hash) ) {
NSData *sha1 = [NSData dataWithBytes:hash length:CC_SHA512_DIGEST_LENGTH];
return sha1;
}
return nil;
}
Put this in a category on NSData, or use it whatever way you like, the code remains the same.
You should've researched your question. I found an answer in one google search.
Can anybody point me in the right direction to be able to encrypt a string, returning another string with the encrypted data? (I've been trying with AES256 encryption.) I want to write a method which takes two NSString instances, one being the message to encrypt and the other being a 'passcode' to encrypt it with - I suspect I'd have to generate the encryption key with the passcode, in a way that can be reversed if the passcode is supplied with the encrypted data. The method should then return an NSString created from the encrypted data.
I've tried the technique detailed in the first comment on this post, but I've had no luck so far. Apple's CryptoExercise certainly has something, but I can't make sense of it... I've seen lots of references to CCCrypt, but it's failed in every case I've used it.
I would also have to be able to decrypt an encrypted string, but I hope that's as simple as kCCEncrypt/kCCDecrypt.
Since you haven't posted any code, it's difficult to know exactly which problems you're encountering. However, the blog post you link to does seem to work pretty decently... aside from the extra comma in each call to CCCrypt() which caused compile errors.
A later comment on that post includes this adapted code, which works for me, and seems a bit more straightforward. If you include their code for the NSData category, you can write something like this: (Note: The printf() calls are only for demonstrating the state of the data at various points — in a real application, it wouldn't make sense to print such values.)
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *key = #"my password";
NSString *secret = #"text to encrypt";
NSData *plain = [secret dataUsingEncoding:NSUTF8StringEncoding];
NSData *cipher = [plain AES256EncryptWithKey:key];
printf("%s\n", [[cipher description] UTF8String]);
plain = [cipher AES256DecryptWithKey:key];
printf("%s\n", [[plain description] UTF8String]);
printf("%s\n", [[[NSString alloc] initWithData:plain encoding:NSUTF8StringEncoding] UTF8String]);
[pool drain];
return 0;
}
Given this code, and the fact that encrypted data will not always translate nicely into an NSString, it may be more convenient to write two methods that wrap the functionality you need, in forward and reverse...
- (NSData*) encryptString:(NSString*)plaintext withKey:(NSString*)key {
return [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
}
- (NSString*) decryptData:(NSData*)ciphertext withKey:(NSString*)key {
return [[[NSString alloc] initWithData:[ciphertext AES256DecryptWithKey:key]
encoding:NSUTF8StringEncoding] autorelease];
}
This definitely works on Snow Leopard, and #Boz reports that CommonCrypto is part of the Core OS on the iPhone. Both 10.4 and 10.5 have /usr/include/CommonCrypto, although 10.5 has a man page for CCCryptor.3cc and 10.4 doesn't, so YMMV.
EDIT: See this follow-up question on using Base64 encoding for representing encrypted data bytes as a string (if desired) using safe, lossless conversions.
I have put together a collection of categories for NSData and NSString which uses solutions found on Jeff LaMarche's blog and some hints by Quinn Taylor here on Stack Overflow.
It uses categories to extend NSData to provide AES256 encryption and also offers an extension of NSString to BASE64-encode encrypted data safely to strings.
Here's an example to show the usage for encrypting strings:
NSString *plainString = #"This string will be encrypted";
NSString *key = #"YourEncryptionKey"; // should be provided by a user
NSLog( #"Original String: %#", plainString );
NSString *encryptedString = [plainString AES256EncryptWithKey:key];
NSLog( #"Encrypted String: %#", encryptedString );
NSLog( #"Decrypted String: %#", [encryptedString AES256DecryptWithKey:key] );
Get the full source code here:
https://gist.github.com/838614
Thanks for all the helpful hints!
-- Michael
#owlstead, regarding your request for "a cryptographically secure variant of one of the given answers," please see RNCryptor. It was designed to do exactly what you're requesting (and was built in response to the problems with the code listed here).
RNCryptor uses PBKDF2 with salt, provides a random IV, and attaches HMAC (also generated from PBKDF2 with its own salt. It support synchronous and asynchronous operation.
I waited a bit on #QuinnTaylor to update his answer, but since he didn't, here's the answer a bit more clearly and in a way that it will load on XCode7 (and perhaps greater). I used this in a Cocoa application, but it likely will work okay with an iOS application as well. Has no ARC errors.
Paste before any #implementation section in your AppDelegate.m or AppDelegate.mm file.
#import <CommonCrypto/CommonCryptor.h>
#implementation NSData (AES256)
- (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
Paste these two functions in the #implementation class you desire. In my case, I chose #implementation AppDelegate in my AppDelegate.mm or AppDelegate.m file.
- (NSString *) encryptString:(NSString*)plaintext withKey:(NSString*)key {
NSData *data = [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
return [data base64EncodedStringWithOptions:kNilOptions];
}
- (NSString *) decryptString:(NSString *)ciphertext withKey:(NSString*)key {
NSData *data = [[NSData alloc] initWithBase64EncodedString:ciphertext options:kNilOptions];
return [[NSString alloc] initWithData:[data AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
}
Please use the below mentioned URL to encrypt string using AES excryption with
key and IV values.
https://github.com/muneebahmad/AESiOSObjC