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

18,765

Solution 1

You need to fix your Java hmac printer, because 4effffffd8ffffffce7cffffffc4ffffffc71b2f72ffffffdc21ffffffa1ffffffe0ffffffe62d32550b0771296bffffff9c1159ffffffdeffffff8675ffffff9928654c isn't valid. All those ffffff in there are a giveaway that you are sign-extending the bytes to 32-bit signed integers before converting them to hex. Presumably the correct hmac is 4ed8ce7cc4c71b2f72dc21a1e0e62d32550b0771296b9c1159de86759928654c.

Anyway, I suspect you are calling your method incorrectly. I copied your code into a test program which gives me this output for your key and data:

2011-12-10 13:03:38.231 hmactest[8251:707] test hmac = <4ed8ce7c c4c71b2f 72dc21a1 e0e62d32 550b0771 296b9c11 59de8675 9928654c>

That matches your desired output (except for the sign-extension errors).

Here's my test program:

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

NSData *hmacForKeyAndData(NSString *key, NSString *data)
{
    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}

int main (int argc, const char * argv[])
{
    @autoreleasepool {
        // Compare to http://en.wikipedia.org/wiki/HMAC#Examples_of_HMAC_.28MD5.2C_SHA1.2C_SHA256_.29
        NSLog(@"empty hmac = %@", hmacForKeyAndData(@"", @""));
        NSLog(@"test hmac = %@", hmacForKeyAndData(@"YARJSuwP5Oo6/r47LczzWjUx/T8ioAJpUK2YfdI/ZshlTUP8q4ujEVjC0seEUAAtS6YEE1Veghz+IDbNQb+2KQ==", @"id=456|time=19:10|nonce=8"));
    }
    return 0;
}

Solution 2

Line

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

has a bug

If in your key would be 0x00 byte strlen(cKey) would give wrong length and hmac generation process will produce some rubbish.

In my implementation I have changed that to:

CCHmac(kCCHmacAlgSHA256, cKey, [key length], cData, [data length], cHMAC);
Share:
18,765
Tushar
Author by

Tushar

A Geek, Entrepreneur ! Building a lot of SaaS applications for SMEs. The recent ones are: https://www.HRStop.com https://www.HiringBull.com https://www.HawkHR.com Recently published two open source projects - Database documenter - http://dbdoc.codeplex.com Database Script Executer - http://sqlexecuter.codeplex.com

Updated on June 14, 2022

Comments

  • Tushar
    Tushar about 2 years

    I need to generate a hash using HMAC SHA256. I am using the following code in Java. I need an equivalent code in Objective-C.

    javax.crypto.Mac mac = javax.crypto.Mac.getInstance(type);
    javax.crypto.spec.SecretKeySpec secret = new javax.crypto.spec.SecretKeySpec(key.getBytes(), type);
    mac.init(secret);
    byte[] digest = mac.doFinal(value.getBytes());      
    StringBuilder sb = new StringBuilder(digest.length * 2);
    String s="";
    for (byte b: digest) {
        s = Integer.toHexString(b);
        if (s.length() == 1) {
            sb.append('0');
        }
        sb.append(s);
    }
    return sb.toString();
    

    Key = YARJSuwP5Oo6/r47LczzWjUx/T8ioAJpUK2YfdI/ZshlTUP8q4ujEVjC0seEUAAtS6YEE1Veghz+IDbNQb+2KQ==

    Value =

    id=456|time=19:10|nonce=8

    Output =

    4effffffd8ffffffce7cffffffc4ffffffc71b2f72ffffffdc21ffffffa1ffffffe0ffffffe62d32550b0771296bffffff9c1159ffffffdeffffff8675ffffff9928654c
    

    I have this Objective-C function:

      //Hash method Definition
        - (NSString *)getHashEncription:(NSString *)key andData:(NSString *)data{
    
            NSLog(@"Secret Key %@ And Data %@", key, data);
    
            const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
            const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
    
    
    
            unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    
            //HmacSHA256
    
            CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    
            NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC
                                                  length:sizeof(cHMAC)];
    
            [Base64 initialize];
            NSString *b64EncStr = [Base64 encode:HMAC];     
            NSLog(@"Base 64 encoded = %@",b64EncStr);   
            NSLog(@"NSData Value %@", HMAC);      
    
        //    unsigned char hashedChars[32];
        //    NSString *inputString;
        //    inputString = [NSString stringWithFormat:@"hello"];
        //    NSData * inputData = [inputString dataUsingEncoding:NSUTF8StringEncoding];
        //    CC_SHA256(inputData.bytes, inputData.length, hashedChars);
    
    
            return [[NSString alloc] initWithData:HMAC encoding:NSASCIIStringEncoding];
    
        }//End of getHashEncription
    

    The output that I am getting is this:

    8736bc4aa7fc3aa071f2b4262b6972a89d2861559a20afa765e46ff17cb181a9
    

    I tried removing the base64 encoding, but it didn't work.

    Any suggestions are most welcome.

  • gdubs
    gdubs over 11 years
    hi, so im having the same problem and your solution helped me solve the inaccuracy of the hmac i generate from ios. my only problem is tho when it returns NSData it the return looks like this <2efb00ab a01a3f5b 674fba30.....> it would basically have spaces. Meanwhile on my API it would be one whole string ("2efb00aba01a3f5b674fba3063b43fee7a93569471...."). I'm using c# btw for the api. my question is do I just remove the spaces so I can pass the correct signature to my api? or do i convert it to string using base64 (this will change the value tho)?
  • Muhammad Saad Ansari
    Muhammad Saad Ansari over 10 years
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); <-- on this line i am getting EXC_BAD_ACESS . Any idea ?
  • CommaToast
    CommaToast over 8 years
    Don't you need to free(cHMAC)? To avoid unbounded memory growth from this? And why isn't it a pointer..?
  • rob mayoff
    rob mayoff over 8 years
    You don't need to free it, because it is allocated on the stack.
  • Olie
    Olie about 8 years
    The problem I'm having is that my particular data (I'm using the same hMac routines you guys are), when I do const char *cData = [data cStringUsingEncoding: NSASCIIStringEncoding];, returns cData = NULL. Now I just have to figure out why. (I have a very narrow "this data worked, now this slightly modified data doesn't" test case, I just need to diff them and figure it out.)
  • rob mayoff
    rob mayoff about 8 years
    There are characters in your data string that do not exist in the ASCII character set.