如何在Cocoa中创build一个string的MD5散列?
我知道SHA-1是首选,但是这个项目需要我使用MD5。
#include <openssl/md5.h> - (NSString*) MD5Hasher: (NSString*) query { NSData* hashed = [query dataUsingEncoding:NSUTF8StringEncoding]; unsigned char *digest = MD5([hashed bytes], [hashed length], NULL); NSString *final = [NSString stringWithUTF8String: (char *)digest]; return final; }
我从StackOverflow上的另一个类似问题的答案中得到了这段代码,但是当程序在返回final时发生了下面的错误:
(gdb) p digest $1 = (unsigned char *) 0xa06310e4 "\0206b\260/\336\316^\021\b\a/9\310\225\204" (gdb) po final Cannot access memory at address 0x0 (gdb) po digest Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_INVALID_ADDRESS at address: 0xb0623630 0x98531ed7 in objc_msgSend () The program being debugged was signaled while in a function called from GDB. GDB has restored the context to what it was before the call. To change this behavior use "set unwindonsignal off" Evaluation of the expression containing the function (_NSPrintForDebugger) will be abandoned.
我无法理解这一点。
这是我使用的类别:
的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
用法
NSString *myString = @"test"; NSString *md5 = [myString MD5String]; // returns NSString of the MD5 of test
cdespinosa和irsk已经向你展示了你的实际问题,所以让我通读你的GDBlogging:
(gdb) p digest $1 = (unsigned char *) 0xa06310e4 "\0206b\260/\336\316^\021\b\a/9\310\225\204"
您已经将digest
打印为Cstring。 你可以在这里看到这个string是原始字节; 因此所有的八进制转义符(例如\020
, \225
)和一对标点符号( /
和^
)。 这不是您所期望的可打印ASCIIhex表示。 你很幸运,它里面没有零字节。 否则,你不会打印整个散列。
(gdb) po final Cannot access memory at address 0x0
final
是nil
。 这是有道理的,因为你的string不是有效的UTF-8; 再次,这只是原始数据字节。 stringWithUTF8String:
需要一个UTF-8编码的文本string; 你没有给它一个,所以它返回nil
。
为了传递原始数据,你需要使用NSData。 在这种情况下,我认为你需要hex表示,所以你需要按照irsk给你的方式创build它。
最后,考虑一下你的input没有散列到有效的UTF-8string是多么的幸运。 如果有的话,你不会注意到这个问题。 你可能想用这个input为这个哈希方法构造一个unit testing。
(gdb) po digest Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_INVALID_ADDRESS at address: 0xb0623630 0x98531ed7 in objc_msgSend ()
您的程序在objc_msgSend
崩溃(具体问题:“访问不良”,“无效地址”)。 这是因为digest
要么根本就不是cocoa/ CF对象,要么是一个,但是被释放了。 在这种情况下,这是因为digest
不是一个cocoa对象; 它是一个C字节数组,如上面的p digest
行所示。
请记住,Objective-C是C的一个超集。所有的C都保持不变。 这意味着有C数组(例如char []
)和Cocoa的NSArrays并排。 此外,由于NSArray来自Cocoa框架,而不是Objective-C语言,因此无法使NSArray对象与C数组互换:不能在Cocoa数组上使用下标运算符,并且无法发送Objective-C消息给C数组。
Facebook使用这个
+ (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; }
或实例方法
- (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; }
我相信digest是一个指向原始二进制散列的指针。 在下一行中,您试图将其解释为UTF-8string,但最有可能不包含合法的UTF-8编码的字符序列。
我期望你想要的是使用任何你认为合适的algorithm,将16字节的unsigned char静态数组转换成32个ASCIIhex字符[0-9a-f]。
MD5函数不返回一个Cstring,它返回一个指向某些字节的指针。 你不能把它当作一个string。
如果你想创build一个string,你需要使用这些字节的hex值来build立一个string。 下面是一个做NSData类别的方法:
#import <CommonCrypto/CommonDigest.h> @implementation NSData (MMAdditions) - (NSString*)md5String { unsigned char md5[CC_MD5_DIGEST_LENGTH]; CC_MD5([self bytes], [self length], md5); return [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15] ]; } @end
我曾经使用过这个方法:
的NSString + MD5.h
@interface NSString (MD5) - (NSString *)MD5; @end
的NSString + MD5.m
#import "NSString+MD5.h" #import <CommonCrypto/CommonDigest.h> @implementation NSString (MD5) - (NSString *)MD5 { const char * pointer = self.UTF8String; unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH]; CC_MD5(pointer, (CC_LONG)strlen(pointer), md5Buffer); NSMutableString * string = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { [string appendFormat:@"%02x", md5Buffer[i]]; } return string; } @end
用法:
NSString * myString = @"test"; NSString * md5 = [myString MD5];
@implementation NSString (MD5) + (NSString *)formattedMD5:(const char *)data length:(unsigned long)len { unsigned char *digest = MD5((unsigned const char *)data, len, NULL); NSMutableArray *values = [[NSMutableArray alloc] init]; for (int i = 0; i < strlen((char *)digest); i++) { char hexValue[4]; sprintf(hexValue, "%02X", digest[i]); [values addObject:[NSString stringWithCString:hexValue length:strlen(hexValue)]]; } // returns a formatted MD5 fingerprint like // 00:00:00:00:00:00:00:00:00 return [values componentsJoinedByString:@":"]; } @end
这些答案是正确的,但令人困惑。 我发布了一个工作示例,因为我遇到了大多数其他问题。 该代码已经过testing,适用于Mac OS X 10.12.x和iOS 10.1.x.
YourClass.h
#import <CommonCrypto/CommonDigest.h> @interface YourClass : NSObject + (NSString *) md5:(NSString *) input; @end
YourClass.m
#import YourClass.h + (NSString *) md5:(NSString *) input { const char *cStr = [input UTF8String]; unsigned char digest[CC_MD5_DIGEST_LENGTH]; CC_MD5(cStr, (uint32_t)strlen(cStr), digest); NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) [output appendFormat:@"%02x", digest[i]]; //%02X for capital letters return output; }
用法(例如在其他一些课堂上):
SomeOtherClass.h
#import "YourClass.h"
SomeOtherClass.m
-(void) Test { //call by [self Test] or use somewhere in your code. NSString *password = @"mypassword123"; NSString *md5 = [YourClass md5:password]; NSLog(@"%@", password); NSLog(@"%@", md5); }
- (NSString*)MD5:(NSData *) data { // Create byte array of unsigned chars unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH]; // Create 16 byte MD5 hash value, store in buffer CC_MD5([data bytes], (CC_LONG)data.length, md5Buffer); // Convert unsigned char buffer to NSString of hex values NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) [output appendFormat:@"%02x",md5Buffer[i]]; return output; }
如何使用
NSString *yourStrToBeConverted; NSData* data = [yourStrToBeConverted dataUsingEncoding:NSUTF8StringEncoding]; NSString *md5res=[self MD5:data];