2009-04-16 12 views
60

Necesito generar HMAC-SHA1 en Objective C. Pero no encontré nada que funcione. Intenté con CommonCrypto, usando CCHMAC, pero no funcionó. Necesito generar un hmac y luego generar el número de HOTP.Código de ejemplo de Objective-C para HMAC-SHA1

¿Alguien tiene algún código de ejemplo en Objective C o C?

+0

yo no entiendo por qué está utilizando º e base64Encoding, si todo lo que queremos es tener una cadena del hash generado. ¿Puedes explicarlo? Porque al final obtenemos un hmac-sha256 codificado en base64, en lugar de un hmac-sha256 ... – bruno

+0

@bruno en caso de que no lo hayas notado, tu respuesta ha sido eliminada y convertida en un comentario. Si tiene más para publicar, publíquelo como una nueva respuesta. –

Respuesta

73

Así es como se genera una HMAC usando SHA-256:

NSString *key; 
NSString *data; 

const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding]; 

unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; 

CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC 
             length:sizeof(cHMAC)]; 

NSString *hash = [HMAC base64Encoding]; 

No estoy al tanto de una biblioteca HOTP, pero el algoritmo era bastante simple, si no recuerdo mal.

+1

base64Encoding tiene en el objeto c? Intenté compilarlo, pero obtengo un error en esta línea. [HMAC base64Encoding]; – Helena

+1

@Helena: oops, base64Encoding es de un protocolo NSData personalizado. =) Me alegro de que el resto del código funcionó, sin embargo. –

+0

Gracias toneladas ... :) – lostInTransit

2

Paso todo un día intentando convertir el hash generado (bytes) en datos legibles. Utilicé la solución codificada en base64 de la respuesta anterior y no funcionó en absoluto para mí (es decir, necesitas una .h externa para poder usar la codificación base64, que yo tenía).

Así que lo que hice fue esto (que funciona perfectamente sin un .h externo):

CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

// Now convert to NSData structure to make it usable again 
NSData *out = [NSData dataWithBytes:cHMAC length:CC_SHA256_DIGEST_LENGTH]; 

// description converts to hex but puts <> around it and spaces every 4 bytes 
NSString *hash = [out description]; 
hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""]; 
hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""]; 
hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""]; 
// hash is now a string with just the 40char hash value in it 
NSLog(@"%@",hash); 
8

Esto funciona sin necesidad de utilizar protocolos personalizados, utilizando un código de http://cocoawithlove.com/2009/07/hashvalue-object-for-holding-md5-and.html

HashSHA256.h

#import <Foundation/Foundation.h> 
#import <CommonCrypto/CommonDigest.h> 

@interface HashSHA256 : NSObject { 


} 

- (NSString *) hashedValue :(NSString *) key andData: (NSString *) data ; 

@end 

HashSHA256.m

#import "HashSHA256.h" 

#import <CommonCrypto/CommonHMAC.h> 


@implementation HashSHA256 


- (NSString *) hashedValue :(NSString *) key andData: (NSString *) data { 


    const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding]; 
    const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding]; 
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; 
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

    NSString *hash; 

    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; 

    for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) 
     [output appendFormat:@"%02x", cHMAC[i]]; 
    hash = output; 
    return hash; 

} 

@end 

Uso:

- (NSString *) encodePassword: (NSString *) myPassword { 
    HashSHA256 * hashSHA256 = [[HashSHA256 alloc] init]; 
    NSString * result = [hashSHA256 hashedValue:mySecretSalt andData:myPassword];  
    return result;  
} 
+1

No debe usar simplemente la cadena como una clave.En su lugar, debe derivarlo y crear una clave adecuada que sea más larga. PBKDF2 sería sin duda un comienzo. –

36

aquí es cómo se puede generar HMAC-SHA1 base 64.

Debe agregar Base64.hy Base64.m a su proyecto. Puede obtenerlo llamando al here.

Si usa ARC, se mostrarán algunos errores en Base64.m. Encuentra las líneas que son similares como esta

return [[[self alloc] initWithBase64String:base64String] autorelease]; 

lo que necesitas es eliminar la sección de liberación automática. El resultado final debería verse así:

return [[self alloc] initWithBase64String:base64String]; 

Ahora en su proyecto general de importación "Base64.h" y el siguiente código

#import "Base64.h" 
#include <CommonCrypto/CommonDigest.h> 
#include <CommonCrypto/CommonHMAC.h> 

- (NSString *)hmacsha1:(NSString *)data secret:(NSString *)key { 

    const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding]; 

    unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH]; 

    CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

    NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)]; 

    NSString *hash = [HMAC base64String]; 

    return hash; 
} 

Con

NSLog(@"Hash: %@", hash); 

obtendrá algo similar a esto:

ghVEjPvxwLN1lBi0Jh46VpIchOc= 

+3

en realidad esta es la respuesta correcta específicamente para el requisito ** HMAC-SHA1 ** en la pregunta – beryllium

+0

¡Ahorrador de tiempo asombroso, gracias! –

+8

Actualización de iOS 7: la línea '[HMAC base64String]' dará un error. En su lugar, debe usar 'base64EncodedStringWithOptions:'. – mafiOSo

22

Ésta es la solución completa que funciona sin ningún tipo de bibliotecas o hacks extra:

+(NSString *)hmac:(NSString *)plainText withKey:(NSString *)key 
{ 
    const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
    const char *cData = [plainText cStringUsingEncoding:NSASCIIStringEncoding]; 

    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; 

    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

    NSData *HMACData = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)]; 

    const unsigned char *buffer = (const unsigned char *)[HMACData bytes]; 
    NSString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2]; 

    for (int i = 0; i < HMACData.length; ++i) 
     HMAC = [HMAC stringByAppendingFormat:@"%02lx", (unsigned long)buffer[i]]; 

    return HMAC; 
} 

No es necesario que incluya ninguna biblioteca de terceros base64, ya que está codificada.

+0

¿Está seguro de que ya está codificada en Base 64? ¿Qué hace que la base 64 esté codificada? Lamento molestarlo, pero estoy solucionando mi dificultad para generar una firma oauth. Intenté usar tu algoritmo, pero me doy cuenta de que no sé/veo dónde está codificado Base 64. – helloB

+2

⚠️ Advertencia a los copiadores: ** tenga cuidado con el tipo de codificación !! ** Estaba codificando caracteres emoji y cambié 'NSASCIIStringEncoding' a' NSUTF16StringEncoding' que introdujo terminadores nulos después de cada carácter en la matriz c devuelta, 'strlen' para pensar que la longitud de la matriz era 1, lo que hizo que HMAC se basara únicamente en el primer carácter. – Warpling

+0

¿Qué es CCHmac? –

2

Así es como yo lo hacen sin archivos externos devolver una cadena hexadecimal:

-(NSString *)hmac:(NSString *)plaintext withKey:(NSString *)key 
{ 
    const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
    const char *cData = [plaintext cStringUsingEncoding:NSASCIIStringEncoding]; 
    unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH]; 
    CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 
    NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)]; 
    const unsigned char *buffer = (const unsigned char *)[HMACData bytes]; 
    NSMutableString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2]; 
    for (int i = 0; i < HMACData.length; ++i){ 
     [HMAC appendFormat:@"%02x", buffer[i]]; 
    } 
    return HMAC; 
} 

Fue probado en Xcode 5 con iOS 7 y funciona bien!

+0

Eso funciona bien para mí ... Gracias ... – Urkman

+0

Gracias es su trabajo para mí .. –

1

Fuera de interés, ¿por qué crea (char sin signo cHMAC) y luego convierte a (NSData) y luego lo convierte en (NSMutableString) y luego convierte finalmente en (HexString)?

Puede hacer esto de una manera más rápida cortando al intermediario (es decir, sin NSData y NSMutableString, rendimiento más rápido y mejor), también cambiando (char sin signo) en (uint8_t []), después de todo, todos son hexadecimales. matrices de todos modos !, a continuación:

-(NSString *)hmac:(NSString *)plaintext withKey:(NSString *)key 
{ 
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
const char *cData = [plaintext cStringUsingEncoding:NSASCIIStringEncoding]; 

uint8_t cHMAC[CC_SHA1_DIGEST_LENGTH]; 

CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

NSString *Hash1 = @""; 
for (int i=0; i< CC_SHA1_DIGEST_LENGTH; i++) 
{ 
    Hash1 = [Hash1 stringByAppendingString:[NSString stringWithFormat:@"%02X", cHMAC[i]]]; 
} 
return Hash1; 
} 

espero que esto ayude,

Saludos

Heider Sati

Cuestiones relacionadas