3

I need to hash a NSData input with HMAC-SHA1. I used this code:

- (NSString *)HMACSHA1:(NSData *)data {
    NSParameterAssert(data);

    const char *cKey = [@"SampleSecretKey012345678" cStringUsingEncoding:NSUTF8StringEncoding];
    const void *cData = [data bytes];

    unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];

    CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);

    NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];\

    /* Returns hexadecimal string of NSData. Empty string if data is empty. */

    const unsigned char *dataBuffer = (const unsigned char *)[HMAC bytes];

    if (!dataBuffer) {
        return [NSString string];
    }

    NSUInteger dataLength = [HMAC length];
    NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];

    for (int i = 0; i < dataLength; ++i) {
        [hexString appendFormat:@"%02x", (unsigned int)dataBuffer[i]];
    }

    return [NSString stringWithString:hexString];
}

but the hex string output is always wrong (checked from server). I think the problem is this line:

const void *cData = [data bytes];

because if convert data (sample "test" string) in the same way as key:

const void *cData = [@"test" cStringUsingEncoding:NSUTF8StringEncoding];

then check the result using this page: HMAC crypt, the result is matched.

If I hash a NSString then I can use cStringUsingEncoding: but I can't figure out convert NSData to const void*. Anyone can help me? Thanks!

zaph
  • 111,848
  • 21
  • 189
  • 228
kientux
  • 1,782
  • 1
  • 17
  • 32

2 Answers2

1

Common Crypto supports HMAC with SHA1, MD5, SHA256, SHA384, SHA512 and SHA224.

Here is an example implementation that is a little simpler, not sure if it resolves yourproblem since no input/desired output was supplied:

- (NSString *)HMACSHA1:(NSData *)data {
    NSParameterAssert(data);

    NSData *keyData = [@"SampleSecretKey012345678" dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableData *hMacOut = [NSMutableData dataWithLength:CC_SHA1_DIGEST_LENGTH];

    CCHmac(kCCHmacAlgSHA1,
           keyData.bytes, keyData.length,
           data.bytes,    data.length,
           hMacOut.mutableBytes);

    /* Returns hexadecimal string of NSData. Empty string if data is empty. */
    NSString *hexString = @"";
    if (data) {
        uint8_t *dataPointer = (uint8_t *)(hMacOut.bytes);
        for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
            hexString = [hexString stringByAppendingFormat:@"%02x", dataPointer[i]];
        }
    }

    return hexString;
}
zaph
  • 111,848
  • 21
  • 189
  • 228
  • Thank you, this works! I never think about just use `data.bytes` and `data.lenght` instead of converting data to cString. How stupid. – kientux Oct 13 '15 at 07:24
0

I'd advise to use CommonCrypto framework from Apple as you have hardware accelerated SHA calculation.

I don't know if it's HMAC (as far as I can see it is supported, but didn't try), but I'd consider switching your server (or whatever) to be compatible, as on the iOS side it's much faster with hardware support.

Edit: You can read more about the topic at this SOF question.

Edit 2: At Github there is also a nice wrapper (Swift) for CommonCrypto. Anyway, it will give you an idea how to implement it and what does CommonCrypto support.

Community
  • 1
  • 1
Nat
  • 12,032
  • 9
  • 56
  • 103
  • Thank you for your suggestion, I think I still need to read more and more about cryptology to understand those things :) – kientux Oct 13 '15 at 07:26