How do I create an MD5 Hash of a string in Cocoa? How do I create an MD5 Hash of a string in Cocoa? objective-c objective-c

How do I create an MD5 Hash of a string in Cocoa?


This is the category I use:

NSString+MD5.h

@interface NSString (MD5)- (NSString *)MD5String;@end

NSString+MD5.m

#import <CommonCrypto/CommonDigest.h>@implementation NSString (MD5)- (NSString *)MD5String {    const char *cStr = [self UTF8String];    unsigned char result[CC_MD5_DIGEST_LENGTH];    CC_MD5( cStr, (CC_LONG)strlen(cStr), result );    return [NSString stringWithFormat:        @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",        result[0], result[1], result[2], result[3],         result[4], result[5], result[6], result[7],        result[8], result[9], result[10], result[11],        result[12], result[13], result[14], result[15]    ];  }@end

Usage

NSString *myString = @"test";NSString *md5 = [myString MD5String]; // returns NSString of the MD5 of test


cdespinosa and irsk have already shown you your actual problem, so let me go through your GDB transcript:

(gdb) p digest$1 = (unsigned char *) 0xa06310e4 "\0206b\260/\336\316^\021\b\a/9\310\225\204"

You've printed digest as a C string. You can see here that this string is raw bytes; hence all the octal escapes (e.g., \020, \225) and the couple of punctuation characters (/ and ^). It is not the printable ASCII hexadecimal representation you were expecting. You're lucky that there were no zero bytes in it; otherwise, you would not have printed the entire hash.

(gdb) po finalCannot access memory at address 0x0

final is nil. This makes sense, as your string above isn't valid UTF-8; again, it's just raw data bytes. stringWithUTF8String: requires a UTF-8-encoded text string; you didn't give it one, so it returned nil.

For passing raw data around, you'd use NSData. In this case, I think you want the hex representation, so you'll need to create that yourself the way irsk showed you.

Finally, consider how lucky you are that your input didn't hash to a valid UTF-8 string. If it had, you wouldn't have noticed this problem. You may want to construct a unit test for this hash method with this input.

(gdb) po digestProgram received signal EXC_BAD_ACCESS, Could not access memory.Reason: KERN_INVALID_ADDRESS at address: 0xb06236300x98531ed7 in objc_msgSend ()

Your program crashed (specific problem: “bad access”, “invalid address”) in objc_msgSend. This is because digest either is not a Cocoa/CF object at all or was one but was freed. In this case, it's because digest is not a Cocoa object; it is a C array of bytes, as shown by your p digest line above.

Remember, Objective-C is a superset of C. All of C exists unchanged in it. That means there are C arrays (e.g., char []) and Cocoa's NSArrays side by side. Moreover, since NSArray comes from the Cocoa framework, not the Objective-C language, there's no way to make NSArray objects interchangeable with C arrays: You can't use the subscript operator on Cocoa arrays, and you can't send Objective-C messages to C arrays.


Facebook uses this

#import <CommonCrypto/CommonDigest.h>

+ (NSString*)md5HexDigest:(NSString*)input {    const char* str = [input UTF8String];    unsigned char result[CC_MD5_DIGEST_LENGTH];    CC_MD5(str, strlen(str), result);    NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];    for(int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {        [ret appendFormat:@"%02x",result[i]];    }    return ret;}

Or instance method

- (NSString *)md5 {    const char* str = [self UTF8String];    unsigned char result[CC_MD5_DIGEST_LENGTH];    CC_MD5(str, (CC_LONG)strlen(str), result);    NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];    for(int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {        [ret appendFormat:@"%02x",result[i]];    }    return ret;}