web-dev-qa-db-fra.com

Comment créer un hachage MD5 d'une chaîne dans Cocoa?

Je sais que SHA-1 est préféré, mais ce projet nécessite que j'utilise 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;
}

J'ai obtenu ce code à partir d'une réponse à une autre question similaire sur StackOverflow, mais j'obtiens l'erreur suivante de GDB lorsque le programme s'arrête à retour 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.

Je ne peux rien y comprendre.

40
demonslayer319

C'est la catégorie que j'utilise:

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

tilisation

NSString *myString = @"test";
NSString *md5 = [myString MD5String]; // returns NSString of the MD5 of test
111
Grant Paul

cdespinosa et irsk vous ont déjà montré votre problème réel, alors laissez-moi parcourir votre transcription GDB:

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

Vous avez imprimé digest en tant que chaîne C. Vous pouvez voir ici que cette chaîne est des octets bruts; d'où tous les échappements octaux (par exemple, \020, \225) et le couple de caractères de ponctuation (/ et ^). Ce n'est pas la représentation hexadécimale ASCII imprimable que vous attendiez. Vous avez de la chance qu'il n'y ait pas zéro octet dedans; sinon, vous n'auriez pas imprimé tout le hachage.

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

final est nil. Cela a du sens, car votre chaîne ci-dessus n'est pas UTF-8 valide; encore une fois, ce ne sont que des octets de données brutes. stringWithUTF8String: nécessite une chaîne de texte encodée en UTF-8; vous ne lui en avez pas donné un, il a donc renvoyé nil.

Pour transmettre des données brutes, vous utiliseriez NSData. Dans ce cas, je pense que vous voulez la représentation hexadécimale, vous devrez donc la créer vous-même comme l'irsk vous l'a montré.

Enfin, considérez votre chance que votre entrée n'ait pas haché une chaîne UTF-8 valide. Si c'était le cas, vous n'auriez pas remarqué ce problème. Vous pouvez vouloir construire un test unitaire pour cette méthode de hachage avec cette entrée.

(gdb) po digest

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0xb0623630
0x98531ed7 in objc_msgSend ()

Votre programme est tombé en panne (problème spécifique: "mauvais accès", "adresse invalide") dans objc_msgSend. En effet, digest n'est pas du tout un objet Cocoa/CF ou en était un mais a été libéré. Dans ce cas, c'est parce que digest n'est pas un objet Cocoa; c'est un tableau d'octets C, comme le montre votre p digest ligne au-dessus.

Rappelez-vous, Objective-C est un surensemble de C. Tout C existe inchangé en lui. Cela signifie qu'il existe des tableaux C (par exemple, char []) et les NSArrays de Cocoa côte à côte. De plus, puisque NSArray provient du framework Cocoa, pas du langage Objective-C, il n'y a aucun moyen de rendre les objets NSArray interchangeables avec les tableaux C: vous ne pouvez pas utiliser l'opérateur d'indice sur les tableaux Cocoa et vous ne pouvez pas envoyer Objective-C messages aux tableaux C.

10
Peter Hosey

Facebook utilise ceci

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

Ou méthode d'instance

- (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;
}
9
Peter Lapisu

J'avais utilisé cette méthode:

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

tilisation:

NSString * myString = @"test";
NSString * md5 = [myString MD5];
4
Nazir

Je crois que le résumé est un pointeur vers un hachage binaire brut. Dans la ligne suivante, vous essayez de l'interpréter comme une chaîne UTF-8, mais il est fort probable qu'elle ne contienne pas de séquences de caractères codées UTF-8 légales.

Je m'attends à ce que vous vouliez convertir le tableau statique de 16 octets de caractères non signés en 32 ASCII caractères hexadécimaux [0-9a-f] en utilisant l'algorithme que vous jugerez bon.

3
cdespinosa

La fonction MD5 ne renvoie pas de chaîne C, elle renvoie un pointeur sur certains octets. Vous ne pouvez pas le traiter comme une chaîne.

Si vous souhaitez créer une chaîne, vous devez créer une chaîne en utilisant les valeurs hexadécimales de ces octets. Voici une façon de le faire en tant que catégorie sur 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
3
Rob Keniger
@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
1
nrj