Obj-C中的MD5结果不匹配

1 投票
2 回答
793 浏览
提问于 2025-04-17 18:33

我尝试用md5算法对一个字符串(十六进制)进行哈希处理。但是,输出的字符串和我在Python或JavaScript(Node.js)中生成的结果不一样。

输入的字符串是:

NSString *input = @"001856413a840871624d6c6f553885b5b16fae345c6bdd44afb26141483bff629df47dbd9ad0";


- (NSString *)md5:(NSString *)input {
// b2b22e766b849b8eb41b22ae85dc49b1
unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];
const char *cStr = [input UTF8String];
CC_MD5_CTX ctx;
CC_MD5_Init(&ctx);
CC_MD5_Update(&ctx, cStr, [input length]);
CC_MD5_Final(md5Buffer, &ctx);

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;

}

在Python中,我这样做:

binaryCredentialString = binascii.unhexlify(input)
# Now MD5 hash the binary string    
m = hashlib.md5()
m.update(binaryCredentialString)
# Hex encode the hash to obtain the final credential string
credential = m.hexdigest()

Python给我的md5输出是正确的,而Objective-C却不对。这是为什么呢?

任何帮助都非常感谢!
- Pascal

2 个回答

3

这基本上和dreamlax的回答是一样的,但你似乎没有理解他的意思。希望我能帮到你(不过如果能帮到你,你应该接受他的回答)。

你的问题在于,你对这个76个字符的字符串 @"001856413a840871624d6c6f553885b5b16fae345c6bdd44afb26141483bff629df47dbd9ad0" 做了MD5加密,而不是对这个字符串所表示的38字节的二进制数据进行加密。

在Python中,你传给 md5 函数的是这个:

binaryCredentialString = binascii.unhexlify(input)

但在ObjC中,你传给它的是这个:

const char *cStr = [input UTF8String];

所以,你需要一个和 unhexlify 功能相同的东西。

我会通过给 NSData 添加 -(NSString *)hexlify 方法,以及给 NSString 添加 -(NSData *)unhexlify 方法来处理这个问题,使用类别来实现。这样你就可以写出和Python一样易读的代码:

- (NSString *)md5:(NSString *)input {
    NSData *binaryCredentialString = [input unhexlify];
    NSMutableData *result = [NSMutableData dataWithLength:CC_MD5_DIGEST_LENGTH];
    CC_MD5([binaryCredentialString bytes],
           [binaryCredentialString length],
           [m mutableBytes]);
    return [result hexlify];
}

那么,如何编写这些类别呢?可以用你的代码和它的反向操作,像这样(这段代码未经测试,需要一些验证和错误处理,但你应该能明白意思):

@implementation NSData(hexlify)
- (NSString *)hexlify {
    unsigned char *buf = [self bytes];
    size_t len = [self length];
    NSMutableString *output = [NSMutableString stringWithCapacity:len * 2];
    for(int i = 0; i < len; i++)
        [output appendFormat:@"%02x",buf[i]];
    return [NSData dataWithData:output];
}
@end

static unsigned char unhexchar(char c) {
    if (c <= '9') return c - '0';
    if (c <= 'F') return c - 'A' + 10;
    return c - 'a' + 10;
}

@implementation NSString(hexlify)
- (NSData *)unhexlify {
    const char *cStr = [self UTF8String];
    size_t len = [self length];
    NSMutableData *output = [NSMutableData dataWithLength:len / 2];
    unsigned char *buf = [output mutableBytes];
    for(int i = 0; i < len / 2; i++)
        buf[i] = unhexchar(cStr[i*2]) * 16 + unhexchar(cStr[i*2+1]);
    return [NSString stringWithString:output];
}
@end

不过我相信只要稍微搜索一下,你就能找到这两个方法的干净、经过测试和优化的实现,而不必自己写。例如,可以看看 这个问题这个问题,以及Stack Overflow上的其他各种问题。

3

在Python中,你是把十六进制的字符串转换回二进制的,但在Objective-C中你没有这么做。你需要把你的字符串解码成一个NSMutableData的实例,然后把[data bytes](和[data length])传给摘要函数。

撰写回答