2010-01-07 4 views
40

Je sais SHA-1 est préféré, mais ce projet nécessite que j'utilise MD5.Comment créer un hachage MD5 d'une chaîne dans Cocoa?

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

Je suis arrivé ce code d'une réponse à une autre question similaire sur StackOverflow, mais je reçois l'erreur suivante de GDB lorsque les interruptions de programme à retour définitif;

(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 pas faire de sens.

Répondre

108

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 

Utilisation

NSString *myString = @"test"; 
NSString *md5 = [myString MD5String]; // returns NSString of the MD5 of test 
+0

Cela fonctionne bien, merci. – demonslayer319

+0

Je l'utilise aussi. Merci! – swdev

+1

Est-ce que cela nécessite IOS6? –

3

Je crois que digest 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 très probable qu'elle ne contienne pas de séquences de caractères codées en UTF-8. Je suppose que ce que vous voulez est de convertir le tableau statique de 16 octets de caractères non signés en 32 caractères hexadécimaux ASCII [0-9a-f] en utilisant n'importe quel algorithme que vous voyez.

2

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 
10

cdespinosa et irsk vous avez déjà montré votre problème réel, alors laissez-moi passer par votre relevé de notes 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 brute octets; donc toutes les échappées octales (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 avait pas zéro octet dedans; sinon, vous n'auriez pas imprimé le hachage entier.

(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 valide UTF-8; encore une fois, ce sont juste des octets de données brutes. stringWithUTF8String: requiert une chaîne de texte codée en UTF-8; vous ne lui avez pas donné un, donc il est retourné nil.

Pour transmettre des données brutes, vous utiliseriez NSData.Dans ce cas, je pense que vous voulez la représentation hexadécimale, donc vous devrez créer cela vous-même comme irsk vous l'a montré. Enfin, considérez la chance que vous avez de ne pas avoir d'entrée dans une chaîne UTF-8 valide. Si c'était le cas, vous n'auriez pas remarqué ce problème. Vous pouvez créer 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 tombé en panne (problème spécifique: « mauvais accès », « adresse non valide ») dans objc_msgSend. C'est parce que 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 C d'octets, comme indiqué par votre ligne p digest ci-dessus. Rappelez-vous, Objective-C est un surensemble de C. Tout le C existe inchangé dans lui. Cela signifie qu'il existe des tableaux C (par exemple char []) et NSARrays de Cocoa côte à côte. De plus, puisque NSArray vient 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 indice sur les tableaux Cocoa et vous ne pouvez pas envoyer Objective-C messages à C arrays.

+0

Poste très utile, merci! – demonslayer319

1
@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 
6

Facebook utilise cette

+ (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 par exemple méthode

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

Si vous ne savez pas d'où vient la constante CC_MD5_DIGEST_LENGTH, il est trouvé en important CommonCrypto/CommonDigest.h dans votre fichier – Christian

3

Je l'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 

Utilisation:

NSString * myString = @"test"; 
NSString * md5 = [myString MD5]; 
+0

+1 pour '(CC_LONG)' contre 'strlen (pointer)' pour traiter les avertissements implicites de conversion et de silence dans Xcode. – andrewbuilder

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

Comment utiliser

NSString *yourStrToBeConverted; 
NSData* data = [yourStrToBeConverted dataUsingEncoding:NSUTF8StringEncoding]; 
NSString *md5res=[self MD5:data]; 
+0

comment appeler cette méthode? –

-1

Ces réponses sont correctes mais déroutantes. Je poste un échantillon de travail, car j'ai eu des problèmes avec la plupart des autres réponses. Le code a été testé et fonctionne bien pour Mac OS X 10.12.x et 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; 
} 

utilisation (par exemple dans une autre classe):

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); 
} 
Questions connexes