Pregunta

Tengo que implementar el HMAC MD5 en la aplicación de mi iPhone. La versión PHP del algoritmo (lado del servidor implementado para verificación) está aquí y no puedo modificarlo (es una API)

function hmac($key, $data) {
    $b = 64; // byte length for md5
    if (strlen($key) > $b) {
        $key = pack("H*",md5($key));            
    }
    $key = str_pad($key, $b, chr(0x00));
    $ipad = str_pad('', $b, chr(0x36));
    $opad = str_pad('', $b, chr(0x5c));
    $k_ipad = $key ^ $ipad ;
    $k_opad = $key ^ $opad;
    $message = $k_opad . pack("H*",md5($k_ipad . $data));
    return base64_encode(md5($message));
}

Encontré un par de implementación del objetivo C:

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

    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];   
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char cHMAC[CC_MD5_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgMD5, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
    NSString *hash = [Base64 encode:HMAC];
    return hash;
}

No devolvió los mismos resultados (PHP! = ObjC).

Jugué con implementaciones de ObjC cambiando la longitud de resumen a 32 (el resultado tiene la misma longitud que la implementación de PHP), la longitud de la clave a 64 (correspondiente al primer str_pad) pero los resultados son siempre diferentes.

¿Alguien puede decirme cómo tener el mismo resultado en Objective-C ??

Editar: dado que las 2 implementaciones en ObjC devuelven el mismo resultado, solo una es útil aquí ...

¿Fue útil?

Solución

Según mi respuesta anterior, el código PHP implementa una variante no estándar del algoritmo HMAC. Este código del objetivo C debería imitarlo. Lo probé en Mac OS X 10.4.11 contra el código PHP para dos combinaciones:

" una tecla corta "
" algún texto "

" Esta es una clave muy larga. Tiene más de 64 bytes, que es la parte importante. & Quot;
" Este es un texto muy largo. Tiene más de 64 bytes, que es la parte importante. & Quot;

- (NSString *)HMACMD5WithKey:(NSString *)key andData:(NSString *)data {
    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
    const unsigned int blockSize = 64;
    char ipad[blockSize], opad[blockSize], keypad[blockSize];
    unsigned int keyLen = strlen(cKey);
    CC_MD5_CTX ctxt;
    if(keyLen > blockSize) {
        //CC_MD5(cKey, keyLen, keypad);
        CC_MD5_Init(&ctxt);
        CC_MD5_Update(&ctxt, cKey, keyLen);
        CC_MD5_Final((unsigned char *)keypad, &ctxt);
        keyLen = CC_MD5_DIGEST_LENGTH;
    } else {
        memcpy(keypad, cKey, keyLen);
    }
    memset(ipad, 0x36, blockSize);
    memset(opad, 0x5c, blockSize);

    int i;
    for(i = 0; i < keyLen; i++) {
      ipad[i] ^= keypad[i];
      opad[i] ^= keypad[i];
    }

    CC_MD5_Init(&ctxt);
    CC_MD5_Update(&ctxt, ipad, blockSize);
    CC_MD5_Update(&ctxt, cData, strlen(cData));
    unsigned char md5[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final(md5, &ctxt);

    CC_MD5_Init(&ctxt);
    CC_MD5_Update(&ctxt, opad, blockSize);
    CC_MD5_Update(&ctxt, md5, CC_MD5_DIGEST_LENGTH);
    CC_MD5_Final(md5, &ctxt);

    const unsigned int hex_len = CC_MD5_DIGEST_LENGTH*2+2;
    char hex[hex_len];
    for(i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        snprintf(&hex[i*2], hex_len-i*2, "%02x", md5[i]);
    }

    NSData *HMAC = [[NSData alloc] initWithBytes:hex length:strlen(hex)];
    NSString *hash = [Base64 encode:HMAC];
    [HMAC release];
    return hash;
}

Otros consejos

Primero, su "ObjC2" está utilizando SHA1, no MD5 (esto significa que probablemente está recibiendo un desbordamiento del búfer ya que SHA1 tiene 20 bytes, mientras que MD5 tiene 16 bytes).

Segundo, creo que hay una variación no estándar en su implementación de PHP HMAC. Observe cómo todas, excepto las últimas invocaciones de md5 (), se envuelven con un paquete (" H * ", ...)? Todos menos el último justo antes de la codificación Base64, es decir. Creo que esto significa que el código PHP es Base64 que codifica la representación 'hexadecimal imprimible' de los datos (32 bytes, cada uno un dígito hexadecimal en ASCII) no el valor 'en bruto' (16 bytes).

Como no puede cambiar la implementación de PHP, tendrá que escribir una implementación de HMAC en el Objetivo C que tenga esta misma variación no estándar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top