11

How to create a SHA256 of a String in iphone/objective c...

Sha256 in Objective-C for iPhone

I have read this..but i am not able to understand this..

I want to create output similar to php funcation as follows:-

$hash = hash_hmac("sha256", implode(';', $hash_parameters), $api_key);

where hash parameters is the array of arguments...

Can you write this as a method which will take the input string...?

And what will be the output of method NSData or NSString..??

I have to create a request with this..??

So in the request object..

[theRequest setHTTPBody:requestBody];

what should be the type of requestBody??

Community
  • 1
  • 1
Kuldeep Singh
  • 1,214
  • 4
  • 18
  • 45
  • This was clearly answered here-> http://stackoverflow.com/questions/3709204/sha256-in-objective-c-for-iphone/11426583#11426583 – Jagadeeshwar Jul 17 '12 at 07:55

5 Answers5

17

I'm not sure I fully understand your questions but if you're looking to create a hashed string you CAN pass in your parameters as arguments to a hash function.

-(void)generateHashedString {

    NSString *key = @"Some random string";
    //enter your objects you want to encode in the data object
    NSString *data = [NSString stringWithFormat:@"%@%@%@", @"sha256", hash_parameters, api_key];

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

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

    NSString *hash = [HMAC base64Encoding];

}

This will give you an NSString of hash that you can use to make your requests. NSLog(@"%@",hash); To see what you generated!

Make sure you #import <CommonCrypto/CommonHMAC.h> too

TALLBOY
  • 1,079
  • 1
  • 10
  • 13
  • This is base64 encoded. You can omit the base64 encoding if you don't need it. – TALLBOY Apr 18 '11 at 22:59
  • then how can i convert the hmac to nsstring type? – Maysam Torabi Apr 19 '11 at 03:55
  • I'd be also interested in the solution, base64Encoding i suppose it's a non-documented feature, and the result is not good anyway. I'm trying this but is not good also: NSString *str = [[NSString alloc] initWithData:HMAC encoding:NSASCIIStringEncoding]; – Cristi Băluță Apr 20 '11 at 13:16
  • Works nicely. I added the ios7 > bases64 encoding as such `NSString *hash = [HMAC base64EncodedStringWithOptions:0];` all good to go. Thanks @TALLBOY – elliotrock Mar 02 '15 at 03:53
3

I didn't compare the following code to the PHP function output but it works for me:

+(NSString *)signWithKey:(NSString *)key usingData:(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);

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

    return [[HMAC.description stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@" " withString:@""];
}

Let me know if it was helpful...

der_michael
  • 3,151
  • 1
  • 24
  • 43
2

I spend a hole day, trying to convert the generated hash (bytes) into readable data. I used the base64 encoded like the answer above and it didn´t work at all for me (b.t.w. you need and an external .h to be able to use the base64 encoding, which i had).

So what i did was this (which works perfectly without an external .h):

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

// Now convert to NSData structure to make it usable again
NSData *out = [NSData dataWithBytes:cHMAC length:CC_SHA256_DIGEST_LENGTH];

// description converts to hex but puts <> around it and spaces every 4 bytes
NSString *hash = [out description];
hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""];
hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""];
hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""];
// hash is now a string with just the 40char hash value in it
NSLog(@"%@",hash);
bruno
  • 2,154
  • 5
  • 39
  • 64
1

For a reference this HMac hashing will work on PHP.

- (NSString *)getToken:(NSString *)queryString
{
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *dateString = [formatter stringFromDate:[NSDate date]];
    NSDate *dateTodayUTC = [formatter dateFromString:dateString];
    NSString *nowTimestamp = [NSString stringWithFormat:@"%.f", [dateTodayUTC timeIntervalSince1970]];

    NSString *hashCombinations = [[NSString alloc] initWithFormat:@"%@%@%.f", queryString, public_api_key, [dateTodayUTC timeIntervalSince1970]];

    const char *privateKey  = [private_api_key cStringUsingEncoding:NSUTF8StringEncoding];
    const char *requestData = [hashCombinations cStringUsingEncoding:NSUTF8StringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];

    //HmacSHA256
    CCHmac(kCCHmacAlgSHA256, // algorithm
           privateKey, strlen(privateKey), // privateKey
           requestData, strlen(requestData), // requestData
           cHMAC); // length

    NSString *hash;
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
    for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02x", cHMAC[i]];
    hash = output;

    NSString *base64HashString = [self base64String:hash];
    self.tokenLabel.text = hash;

    NSLog(@"generated hash = %@", hash);
    NSLog(@"base64 hash = %@", base64HashString);
    NSLog(@"timestamp = %@ nsdate utc = %@", nowTimestamp, dateString);
    NSLog(@"combinations %@", hashCombinations);
    return [base64HashString urlencode];
}

You can use this base64 method.

- (NSString *)base64String:(NSString *)str
{
    NSData *theData = [str dataUsingEncoding: NSASCIIStringEncoding];
    const uint8_t* input = (const uint8_t*)[theData bytes];
    NSInteger length = [theData length];

    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
    uint8_t* output = (uint8_t*)data.mutableBytes;

    NSInteger i;
    for (i=0; i < length; i += 3) {
        NSInteger value = 0;
        NSInteger j;
        for (j = i; j < (i + 3); j++) {
            value <<= 8;

            if (j < length) {
                value |= (0xFF & input[j]);
            }
        }

        NSInteger theIndex = (i / 3) * 4;
        output[theIndex + 0] =                    table[(value >> 18) & 0x3F];
        output[theIndex + 1] =                    table[(value >> 12) & 0x3F];
        output[theIndex + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : '=';
        output[theIndex + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : '=';
    }

    return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}
John Paul Manoza
  • 1,735
  • 25
  • 22
0

I think it's more compact solution:

#import <CommonCrypto/CommonCrypto.h>

...

-(NSData*)Sha256WithKey:(NSData*)key andData:(NSData*)data{
     NSMutableData* result = [NSMutableData 
                               dataWithCapacity:CC_SHA256_DIGEST_LENGTH];

     CCHmac(kCCHmacAlgSHA256, [key bytes], [key length],
            [data bytes], [data length], result.mutableBytes);

     return result;
 }
 ....
Denis Kreshikhin
  • 8,856
  • 9
  • 52
  • 84