Objective-C中的MD5算法

134

如何在Objective-C中计算MD5?


1
我猜你可以相对容易地移植一个计算MD5的C例程。而且它们很容易找到。 - Artelius
5个回答

220

在iPhone上,可以将MD5作为NSStringNSData的附加项添加,例如以下方法:

MyAdditions.h

@interface NSString (MyAdditions)
- (NSString *)md5;
@end

@interface NSData (MyAdditions)
- (NSString*)md5;
@end

MyAdditions.m

#import "MyAdditions.h"
#import <CommonCrypto/CommonDigest.h> // Need to import for CC_MD5 access

@implementation NSString (MyAdditions)
- (NSString *)md5
{
    const char *cStr = [self UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5( cStr, (int)strlen(cStr), result ); // This is the md5 call
    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

@implementation NSData (MyAdditions)
- (NSString*)md5
{
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5( self.bytes, (int)self.length, result ); // This is the md5 call
    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

编辑

添加NSData md5,因为我自己需要,并认为这是保存这个小片段的好地方...

这些方法已经使用NIST MD5测试向量进行验证, http://www.nsrl.nist.gov/testdata/


这不是关于文件的问题。如果您想使用这些方法从文件创建MD5,则可以执行NSData *fileContents = [NSData dataWithContentsOfFile:@"<yourPath>"]; NSString *myHash = [fileContents md5]; 是的,这将把整个文件读入内存。如果您找到适用于文件流的解决方案,请将其发布为答案。 - Klaas
1
如果您需要对文件进行哈希,请使用CC_MD5_Init,然后对所有文件数据使用CC_MD5_Update,最后使用CC_MD5_Finish。 - Nickolay Olshevsky
7
编译64位架构时,调用strlen函数会产生警告:“隐式转换导致整数精度丢失:'unsigned long'转换为'CC_LONG'(也称为'unsigned int')”。 - MaxGabriel
没有可见的 @interface 来声明 'ViewController' 的选择器 'UTF8String',有什么建议吗? - nonickname
@neo999 - 看起来你正在尝试在UIViewController实例上调用UTF8String方法。在上面的代码中,@epatel在NSString类别上实现了一个实例方法md5。因此,一个NSString实例,比如说值为“Hello, World!”的myString将会这样被调用:[myString md5],然后md5方法将返回“65a8e27d8879283831b664bd8b7f0ad4”。 - seeker12
显示剩余2条评论

55

您可以使用内置的Common Crypto库来进行操作。

记得导入:

#import <CommonCrypto/CommonDigest.h>

接着:

- (NSString *) md5:(NSString *) input
{
    const char *cStr = [input UTF8String];
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5( cStr, strlen(cStr), digest ); // This is the md5 call

    NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];

    for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
    [output appendFormat:@"%02x", digest[i]];

    return  output;
}

我实现了以上代码,但在运行应用程序时崩溃了(CC_MD5(cStr,strlen(cStr),digest)---->这一行抛出异常,称为EXC_BAD_ACCESS)。 - Nilesh Kumar
4
这篇答案比其他答案更易读;它需要在strlen之前加上(int)转换,例如(int)strlen... - brandonscript
@Ayaz MD5 无法被解密(至少不能用简单的方法)。 - albanx
只是想指出一个细节,但你应该返回[output copy];否则你实际上返回的是一个NSMutableString。 - Goles
1
@Ayaz - MD5是一种128位的密码哈希函数,由Ronald Rivest于1991年设计,但后来被发现在密码学上存在漏洞。然而,密码哈希函数被称为“单向函数”,正是因为它不能被“解密”,所以它非常有用。它被设计为接受任意长度的输入,例如文本文档,并输出一个固定长度的哈希值。因此,可以使用相同的函数对原始输入进行哈希,并将其与问题输入的哈希进行比较;如果两个输出完全相同,则原始输入肯定未被修改。 - seeker12
显示剩余2条评论

9
如果性能很重要,您可以使用这个经过优化的版本。它比使用 stringWithFormatNSMutableString 的版本快大约5倍。
这是一个 NSString 的类别。
- (NSString *)md5
{
    const char* cStr = [self UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, strlen(cStr), result);

    static const char HexEncodeChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    char *resultData = malloc(CC_MD5_DIGEST_LENGTH * 2 + 1);

    for (uint index = 0; index < CC_MD5_DIGEST_LENGTH; index++) {
        resultData[index * 2] = HexEncodeChars[(result[index] >> 4)];
        resultData[index * 2 + 1] = HexEncodeChars[(result[index] % 0x10)];
    }
    resultData[CC_MD5_DIGEST_LENGTH * 2] = 0;

    NSString *resultString = [NSString stringWithCString:resultData encoding:NSASCIIStringEncoding];
    free(resultData);

    return resultString;
}

1

该链接涵盖了许多答案中使用的通用加密技术。 - zaph
1
算法确实是一样的。但请注意,实现自己的加密算法可能会引入缺陷。在所有情况下都正确地进行硬化需要很多工作。因此,在通常情况下,最好使用库版本。 - vpathak

0

既然有人要求文件流版本,我修改了Joel Lopes Da Silva的一个小代码片段,它可以使用MD5、SHA1和SHA512,并且使用流。它是为iOS设计的,但在OSX上只需进行最小的更改即可(删除ALAssetRepresentation方法)。它可以针对给定文件路径或ALAssets(使用ALAssetRepresentation)生成校验和。它将数据分成小包,使内存影响最小,无论文件大小/资产大小。

它目前位于github这里:https://github.com/leetal/FileHash


Joel发布的代码存在竞态条件,看起来你的代码可能会继承它。请参阅我在Joel帖子上发布的评论。https://www.joel.lopes-da-silva.com/2010/09/07/compute-md5-or-sha-hash-of-large-file-efficiently-on-ios-and-mac-os-x/ - xyzzycoder
谢谢!现在已经修复了。这对我来说从来不是问题,因为在原始实现中,我总是在专用线程中运行它 ;) - Widerberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接