Pergunta

Eu tenho que implementar o HMAC MD5 no meu iPhone app. A versão PHP do algoritmo (lado do servidor implementado para verificação) está aqui e eu não posso modificá-lo (é uma 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));
}

Eu encontrei um par de implementação objective-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;
}

Não retornam os mesmos resultados (PHP! = ObjC).

I tocada com implementações ObjC mudando o comprimento digerir a 32 (resultar em seguida, tem o mesmo comprimento do que a implementação PHP), o comprimento da chave de 64 (correspondente ao primeiro str_pad), mas os resultados são sempre differents.

Alguém pode me dizer como ter o mesmo resultado em Objective-C ??

Edit: desde os 2 implementações em ObjC retornar o mesmo resultado só é útil aqui ..

Foi útil?

Solução

De acordo com a minha resposta anterior, o PHP implementa código uma variante não-padrão do algoritmo HMAC. Este código Objective C deve imitá-lo. Eu testei no Mac OS X 10.4.11 contra o código PHP para duas combinações:

"uma chave curta"
"Algum texto"

"Esta é uma chave muito tempo. É mais de 64 bytes, que é a parte mais importante."
"Este é um texto muito longo. É mais de 64 bytes, que é a parte mais importante."

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

Outras dicas

Em primeiro lugar, o seu “ObjC2” está usando SHA1, não MD5 (Isto significa que provavelmente estão recebendo uma saturação de buffer desde SHA1 é de 20 bytes, enquanto MD5 é de 16 bytes).

Em segundo lugar, eu acho que há uma variação não-padrão em sua implementação PHP HMAC. Observe como todos, mas os últimos invocações de md5 () são envolvidas com um pacote ( "H *", ...)? Todos menos o último direito antes da codificação Base64, isto é. Eu penso que isto significa que o código PHP está na base 64 que codifica a representação 'hex imprimível' dos dados (32 octetos, cada um dígitos hexadecimal em ASCII) não o valor 'bruto' (16 bytes).

Uma vez que você não pode alterar a implementação PHP, você terá que escrever uma implementação HMAC em Objective C que tem essa mesma variação não-padrão.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top