1

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.

ricardopereira
  • 11,118
  • 5
  • 63
  • 81
leolobato
  • 2,359
  • 3
  • 32
  • 51

3 Answers3

3

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
  • 21,597
  • 12
  • 64
  • 64
  • 1
    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 Feb 19 '09 at 14:14
2

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
  • 8,813
  • 3
  • 35
  • 35
  • 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 Mar 21 '09 at 20:23
1

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
  • 51,577
  • 12
  • 107
  • 152
  • 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 Feb 19 '09 at 13:41
  • 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 Feb 19 '09 at 14:06
  • Without knowing exactly what hmac_sha1 returns it's difficult to be sure, but Will Harris might be on to something. – Stephen Darlington Feb 19 '09 at 14:14
  • Yep. That was it. Now I'm on to base64 encode it. :) Thank you! – leolobato Feb 19 '09 at 14:17