如何在 Cocoa 中创建字符串的 MD5 哈希值?

发布于 2024-08-16 22:14:33 字数 1082 浏览 5 评论 0原文

我知道 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 上另一个类似问题的答案中得到了这段代码,但是当程序在返回最终时中断时,我从 GDB 收到以下错误;

(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.

我无法理解它。

I know SHA-1 is preferred, but this project requires I use 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;
}

I got this code from an answer to another similar question on StackOverflow, but I get the following error from GDB when the program breaks at return 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.

I can't make any sense of it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

九公里浅绿 2024-08-23 22:14:33

这是我使用的类别:

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

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
朮生 2024-08-23 22:14:33

cdespinosa 和 irsk 已经向您展示了您的实际问题,所以让我看一下您的 GDB 记录:

(gdb) p 摘要
$1 = (无符号字符*) 0xa06310e4 "\0206b\260/\336\316^\021\b\a/9\310\225\204"

您已将 digest 打印为 C 字符串。你可以在这里看到这个字符串是原始字节;因此,所有八进制转义符(例如 \020\225)和几个标点符号(/^)。它不是您期望的可打印 ASCII 十六进制表示形式。你很幸运,里面没有零字节;否则,您将不会打印整个哈希值。

(gdb) po 最终
无法访问地址 0x0 处的内存

finalnil。这是有道理的,因为上面的字符串不是有效的 UTF-8;同样,这只是原始数据字节。 stringWithUTF8String:需要UTF-8编码的文本字符串;你没有给它一个,所以它返回nil

为了传递原始数据,您可以使用 NSData。在这种情况下,我认为您需要十六进制表示形式,因此您需要按照 irsk 向您展示的方式自行创建。

最后,考虑一下您的输入没有哈希为有效的 UTF-8 字符串是多么幸运。如果有的话,您就不会注意到这个问题。您可能希望使用此输入构建此哈希方法的单元测试。

(gdb) po 摘要

程序收到信号 EXC_BAD_ACCESS,无法访问内存。
原因:KERN_INVALID_ADDRESS,地址:0xb0623630
objc_msgSend () 中的 0x98531ed7

您的程序在 objc_msgSend 中崩溃(具体问题:“访问错误”、“地址无效”)。这是因为 digest 要么根本不是 Cocoa/CF 对象,要么曾经是一个但已被释放。在本例中,这是因为 digest 不是 Cocoa 对象;它是一个 C 字节数组,如上面的 pdigest 行所示。

请记住,Objective-C 是 C 的超集。所有 C 都在其中保持不变。这意味着 C 数组(例如,char [])和 Cocoa 的 NSArray 并排存在。此外,由于 NSArray 来自 Cocoa 框架,而不是 Objective-C 语言,因此无法使 NSArray 对象与 C 数组互换:您不能在 Cocoa 数组上使用下标运算符,也不能发送 Objective-发送至 C 数组的 C 消息。

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 final
Cannot 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 digest

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0xb0623630
0x98531ed7 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.

久而酒知 2024-08-23 22:14:33

Facebook 使用此

#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 实例方法

- (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;
}

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;
}
乱世争霸 2024-08-23 22:14:33

我用过这个方法:

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

I had used this method:

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

Usage:

NSString * myString = @"test";
NSString * md5 = [myString MD5];
会发光的星星闪亮亮i 2024-08-23 22:14:33

我相信摘要是指向原始二进制哈希的指针。在下一行中,您尝试将其解释为 UTF-8 字符串,但它很可能不包含合法的 UTF-8 编码字符序列。

我希望您想要的是使用您认为合适的任何算法将 unsigned char 的 16 字节静态数组转换为 32 个 ASCII 十六进制字符 [0-9a-f]。

I believe that digest is a pointer to a raw binary hash. In the next line you're attempting to interpret it as a UTF-8 string, but it is most likely not to contain legal UTF-8-encoded character sequences.

I expect what you want is to convert the 16-byte static array of unsigned char into 32 ASCII hexadecimal characters [0-9a-f] using whatever algorithm you see fit.

风为裳 2024-08-23 22:14:33

MD5函数不返回C字符串,它返回指向某些字节的指针。你不能把它当作一个字符串。

如果要创建字符串,则需要使用这些字节的十六进制值构建字符串。这是将其作为 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

The MD5 function does not return a C string, it returns a pointer to some bytes. You can't treat it as a string.

If you want to create a string, you need to build a string using the hex values of those bytes. Here is one way to do it as a category on 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
梦归所梦 2024-08-23 22:14:33
@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
@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
谈下烟灰 2024-08-23 22:14:33

这些答案是正确的,但令人困惑。我发布了一个工作示例,因为我对大多数其他答案都有疑问。该代码经过测试,适用于 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);
}

These answers are correct but confusing. I post a working sample, since I had issues with most other answers. The code is tested and works well for Mac OS X 10.12.x and 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;
}

Usage (e.g. in some other class):

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);
}
凡间太子 2024-08-23 22:14:33
- (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];
- (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;
    }

How to use

NSString *yourStrToBeConverted;
NSData* data = [yourStrToBeConverted dataUsingEncoding:NSUTF8StringEncoding];
NSString *md5res=[self MD5:data];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文