kientux
kientux

Reputation: 1792

HMAC SHA1 with NSData input Objective-C

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!

Upvotes: 3

Views: 1654

Answers (2)

zaph
zaph

Reputation: 112857

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;
}

Upvotes: 1

Nat
Nat

Reputation: 12942

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.

Upvotes: 0

Related Questions