views:

1623

answers:

3

Hi,

I'm trying to use a function that has the following signature to sign a HTTP request:

extern void hmac_sha1(const unsigned char *inText, int inTextLength, unsigned char* inKey, const unsigned int inKeyLength, unsigned char *outDigest);

And this is the method I wrote to use it:

- (NSString *)sign: (NSString *)stringToSign {
NSString *secretKey = @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const unsigned char *inText = (unsigned char *)[stringToSign UTF8String];
int inTextLength = [stringToSign length];
unsigned char *inKey = (unsigned char *)[secretKey UTF8String];
const unsigned int inKeyLength = (unsigned int)[secretKey length];
unsigned char *outDigest;

hmac_sha1(inText, inTextLength, inKey, inKeyLength, outDigest);
NSString *output = [NSString stringWithUTF8String:(const char *)outDigest];

return output;

}

The problem is I'm sure this is not the way I'm supposed to do this casting, as inside this hmac_sha1 function I get a EXC_BAD_ACCESS exception.

Since I am new to Objective-C and have close to no experience in C (surprise!) I don't really know what to search for. Any tips on how I can start solving this?

Thanks in advance!

Btw, I got the reference for this function here in stackoverflow.

+1  A: 

Are you sure you don't need to allocate some memory for outDigest before calling hmac_sha1? Since you pass in a pointer, rather than a pointer to a pointer, there's no way that the memory can be allocated inside the routine.

Stephen Darlington
I believe you're right. Looking through the code in http://www.koders.com/c/fid716FD533B2D3ED4F230292A6F9617821C8FDD3D4.aspx it appears that it expects outDigest to be 20 bytes long.
Paul Tomblin
How do I do this? I tried unsigned char *outDigest = (unsigned char *)malloc(64*sizeof(char)); and unsigned char outDigest[20]; but I couldn't get to cast the result to an actual NSString. (but at least the exception is gone!)
leolobato
Without knowing exactly what hmac_sha1 returns it's difficult to be sure, but Will Harris might be on to something.
Stephen Darlington
Yep. That was it. Now I'm on to base64 encode it. :) Thank you!
leolobato
+1  A: 

It looks like the problem is not with the casting, but with outDigest. The fifth argument to hmac_sha1 should point to an already allocated buffer of size 20 bytes (I think).

If you change the line that says

unsigned char *outDigest;

to say

#define HMACSHA1_DIGEST_SIZE 20
void *outDigest = malloc(HMACSHA1_DIGEST_SIZE);

That should get you past the crash inside hmac_sha1.

Then you've got the problem of converting the data at outDigest into an NSString. It looks like hmac_sha1 will put 20 bytes of random-looking data at outDigest, and not a null terminated UTF-8 string, so stringWithUTF8String: won't work. You might want to use something like this instead if you have to return an NSString:

NSString *output = [[NSString alloc] initWithBytesNoCopy:outDigest
                                     length:HMACSHA1_DIGEST_SIZE
                                     encoding:NSASCIIStringEncoding
                                     freeWhenDone:YES];

I don't think NSString is really the right type for the digest, so it might be worth changing your method to return an NSData if you can.

Will Harris
That solved it. I'm still going to Base64 encode it, so I can use as a HTTP GET parameter, so I have to keep it in a NSString. Thank you!
leolobato
A: 

This wasn't part of your question but it's a bug nonetheless, you shouldn't use -length to get the byte count of an UTF8 string. That method returns the number of Unicode characters in the string, not the number of bytes. What you want is -lengthOfBytesUsingEncoding:.

NSUInteger byteCount = [stringToSign lengthOfBytesUsingEncoding:NSUTF8StringEncoding];

Also be aware that the result does not account for a terminating NULL character.

Ashley Clark
Not sure why this got voted down but it's a legitimate issue with the code above. Especially if stringToSign contains any multi-byte UTF8 characters. In that situation the value returned by length will not match the number of bytes returned by UTF8String.
Ashley Clark