19

So I'm trying to figure out how to do a hmacshad256 hash on ios as that's the hash I did for the wcf service api I made. I've been trying to look for some info about it but would usually just end up getting a SHA-256 hash.

This is the only reference I have:

Need to generate HMAC SHA256 hash in Objective C as in Java

And I'm not sure if that's the only way to do it (importing a java hmac class)

Any help is appreciated.

Thanks!

Community
  • 1
  • 1
gdubs
  • 2,724
  • 9
  • 55
  • 102
  • hmm.. somebody removed the response to this earlier? – gdubs Jan 25 '13 at 22:53
  • Is this not what you were looking for? http://stackoverflow.com/questions/5862207/implementing-hmac-encryption-algorithm-in-iphone-application – DenNukem May 15 '13 at 17:44

3 Answers3

36
NSString * parameters = @"string to hash"
NSString *salt = @"saltStringHere";
NSData *saltData = [salt dataUsingEncoding:NSUTF8StringEncoding];
NSData *paramData = [parameters dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData* hash = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH ];
CCHmac(kCCHmacAlgSHA256, saltData.bytes, saltData.length, paramData.bytes, paramData.length, hash.mutableBytes);
NSString *base64Hash = [hash base64Encoding];

and also

#import <CommonCrypto/CommonHMAC.h>

Since base64Encoding is deprecated from iOS 7.0, the last line should be:

NSString *base64Hash = [hash base64EncodedStringWithOptions:0];
Collin
  • 6,720
  • 4
  • 26
  • 29
Juraj Antas
  • 3,059
  • 27
  • 37
  • 2
    The selector now would be -base64EncodedStringWithOptions: – ff10 Feb 16 '14 at 21:19
  • 1
    Please edit your answer, and write that we need to add #import "NSData+Base64.h" – SteBra Jun 17 '14 at 09:26
  • 1
    @Stebra Well, you don't need to import NSData+Base64.h. You can put this fragment of code anywhere you want. But it is true that having category extending NSData is perhaps the best way to do it. – Juraj Antas Jun 18 '14 at 08:02
  • 1
    Since salts are usually public, this may be misleading. It's actually the secret key you should use there! – Raphael Jun 06 '17 at 12:09
8

Here is the solution I'm submitting that I put together from other answers on the matter:

This is easily adapted to other hash types by changing CC_SHA256_DIGEST_LENGTH and kCCHmacAlgSHA256.

If you're interested in doing that, check out the CommonDigest.h file within the CommonCrypto library.

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>

+ (NSString *)hmac:(NSString *)plaintext withKey:(NSString *)key
{
    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [plaintext cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
    const unsigned char *buffer = (const unsigned char *)[HMACData bytes];
    NSMutableString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2];
    for (int i = 0; i < HMACData.length; ++i){
        [HMAC appendFormat:@"%02x", buffer[i]];
    }

    return HMAC;
}

This has been tested on iOS 8.x and iOS 7.x

Alex Zavatone
  • 4,106
  • 36
  • 54
  • 2
    This assumes that the plaintext and key are ASCII, that is very restrictive in today's environment of many languages and even emoji. Notice that @Juraj Antas did not need char array. The only thing that this implementation offers is hex output instead of Base64, it would be worth mentioning that at the top of the answer. – zaph Jun 24 '15 at 19:54
  • Thanks Zaph. Yeah, in my case, I know they are. – Alex Zavatone Sep 02 '15 at 13:35
  • 4
    This is an answer so "in my case" does not apply. Instead of using `NSASCIIStringEncoding` just use `NSUTF8StringEncoding`. – zaph Sep 02 '15 at 13:42
  • https://stackoverflow.com/users/451475/zaph, as this method currently is, even with replacing the `NSASCIIStringEncoding` with `NSUTF8StringEncoding` it returns the wrong hash using high ASCII characters, like these: `¥€£•‹›`. Am working on a fix. – Alex Zavatone Jun 06 '17 at 18:48
1

+ (NSString *)hmacSHA256EncryptString{


    NSString * parameterSecret = @"input secret key";
    NSString *plainString = @"input encrypt content string";
    const char *secretKey  = [parameterSecret cStringUsingEncoding:NSUTF8StringEncoding];
    const char *plainData = [plainString cStringUsingEncoding:NSUTF8StringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, secretKey, strlen(secretKey), plainData, strlen(plainData), cHMAC);
    NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
    const unsigned char *bufferChar = (const unsigned char *)[HMACData bytes];
    NSMutableString *hmacString = [NSMutableString stringWithCapacity:HMACData.length * 2];
    for (int i = 0; i < HMACData.length; ++i){
        [hmacString appendFormat:@"%02x", bufferChar[i]];
    }
    return hmacString;
    
}
KBVSMJ
  • 39
  • 3