Подтвердить что ты не робот

Как создать хэширование MD5 строки в Cocoa?

Я знаю, что 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, когда программа ломается при возврате 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.

Я не могу этого толковать.

4b9b3361

Ответ 1

Это категория, которую я использую:

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

Ответ 2

cdespinosa и irsk уже показали вам вашу актуальную проблему, поэтому позвольте мне пройти через вашу расшифровку GDB:

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

Вы напечатали digest как строку C. Вы можете видеть здесь, что эта строка - это сырые байты; следовательно, все восьмеричные escape-последовательности (например, \020, \225) и пара знаков препинания (/ и ^). Это не печатное ASCII шестнадцатеричное представление, которое вы ожидали. Вам повезло, что в нем не было нулевых байтов; в противном случае вы бы не печатали весь хэш.

(gdb) po final
Cannot access memory at address 0x0

final составляет nil. Это имеет смысл, так как ваша строка выше недействительна UTF-8; опять же, это просто необработанные байты данных. stringWithUTF8String: требуется текстовая строка в кодировке UTF-8; вы не дали его, поэтому он вернулся nil.

Для передачи необработанных данных вы должны использовать NSData. В этом случае, я думаю, вам нужно шестнадцатеричное представление, поэтому вам нужно будет создать это сами, как показал вам irsk.

Наконец, подумайте, как вам повезло, что ваш вход не сделал хеш для допустимой строки UTF-8. Если бы это было так, вы бы не заметили эту проблему. Вы можете создать unit test для этого хэш-метода с этим вводом.

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

Ответ 3

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

Ответ 4

Я считаю, что дайджест является указателем на исходный двоичный хеш. В следующей строке вы пытаетесь интерпретировать ее как строку UTF-8, но, скорее всего, не должны содержать законные последовательности символов в кодировке UTF-8.

Я ожидаю, что вы хотите преобразовать 16-байтовый статический массив unsigned char в 32 шестнадцатеричных символа ASCII [0-9a-f], используя любой алгоритм, который вам подходит.

Ответ 5

Функция 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

Ответ 6

Я использовал этот метод:

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

Ответ 7

@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

Ответ 8

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

Ответ 9

Эти ответы правильные, но сбивающие с толку. Я размещаю рабочий образец, так как у меня были проблемы с большинством других ответов. Код протестирован и хорошо работает для 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);
}