2010-01-07 13 views
40

Sé que SHA-1 es preferible, pero este proyecto requiere que use MD5.¿Cómo creo un Hash MD5 de una cadena en 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; 
} 

Tengo este código de una respuesta a otra pregunta similar en StackOverflow, pero me sale el siguiente error del BGF cuando el programa se rompe en retorno 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. 

No puedo hacer ningún sentido.

Respuesta

108

Ésta es la categoría que utilizo:

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 

Uso

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

Esto funciona bien, gracias. – demonslayer319

+0

Yo uso esto también. ¡Gracias! – swdev

+1

¿Esto requiere IOS6? –

3

Creo que el resumen es un puntero a un hash binario en bruto. En la línea siguiente, intenta interpretarlo como una cadena UTF-8, pero es muy probable que no contenga secuencias de caracteres legales codificadas en UTF-8.

Espero que lo que quiere es convertir la matriz estática de 16 bytes de caracteres sin signo en 32 caracteres hexadecimales ASCII [0-9a-f] utilizando el algoritmo que considere adecuado.

2

La función MD5 no devuelve una cadena C, sino que devuelve un puntero a algunos bytes. No puedes tratarlo como una cadena.

Si desea crear una cadena, debe construir una cadena utilizando los valores hexadecimales de esos bytes. Aquí es una manera de hacerlo como una categoría en 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 y Irsk ya que han demostrado su problema real, así que vamos a ir a través de su transcripción BGF:

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

Imprimió digest como una cadena en C. Aquí puede ver que esta cadena es bytes sin procesar; de ahí todos los escapes octales (por ejemplo, \020, \225) y el par de caracteres de puntuación (/ y ^). No es la representación hexadecimal ASCII imprimible que estaba esperando. Tienes suerte de que no haya cero bytes en él; de lo contrario, no habría impreso todo el hash.

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

final es nil. Esto tiene sentido, ya que su cadena anterior no es válida UTF-8; de nuevo, solo son bytes de datos brutos. stringWithUTF8String: requiere una cadena de texto codificada en UTF-8; no le diste uno, por lo que devolvió nil.

Para pasar datos sin procesar, utilizaría NSData.En este caso, creo que quieres la representación hexadecimal, por lo que tendrás que crearla tú mismo de la manera que te mostró irsk.

Por último, tenga en cuenta la suerte que tiene su entrada no hash a una cadena UTF-8 válida. Si lo hubiera hecho, no habrías notado este problema. Es posible que desee construir una prueba unitaria para este método hash con esta entrada.

(gdb) po digest 

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

Su programa bloqueado (problema específico: “mal acceso”, “dirección no válida”) en objc_msgSend. Esto se debe a que digest no es un objeto Cocoa/CF o fue uno pero se liberó. En este caso, es porque digest no es un objeto Cocoa; es una matriz C de bytes, como se muestra en su línea p digest arriba.

Recuerde, Objective-C es un superconjunto de C. Todo el C existe sin cambios en él. Eso significa que hay conjuntos C (por ejemplo, char []) y NSArrays de Cocoa uno al lado del otro. Además, dado que NSArray proviene del framework Cocoa, no del lenguaje Objective-C, no hay forma de que los objetos NSArray sean intercambiables con los arrays C: no se puede usar el operador subíndice en los arreglos Cocoa, y no se puede enviar Objective-C mensajes a C arrays.

+0

Publicación muy útil, gracias! – 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 utiliza esta

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

O instancia de método

- (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 no sabe dónde viene la constante CC_MD5_DIGEST_LENGTH, se encuentra al importar CommonCrypto/CommonDigest.h en su archivo – Christian

3

que había utilizado este método:

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 

Uso:

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

+1 para '(CC_LONG)' contra 'strlen (puntero)' para abordar la conversión implícita y las advertencias de silencio en 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; 
    } 

Cómo utilizar

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

cómo llamar a este método? –

-1

Estas respuestas son correctas pero confusas. Publiqué una muestra de trabajo, ya que tuve problemas con la mayoría de las otras respuestas. El código ha sido probado y funciona bien para Mac OS X 10.12.xy 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; 
} 

uso (por ejemplo, en alguna otra clase):

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