HMAC - PHP 算法在 Objective-C 中的实现

发布于 2024-08-09 05:09:57 字数 1288 浏览 5 评论 0原文

我必须在我的 iPhone 应用程序中实现 HMAC MD5。该算法的 PHP 版本(用于验证的服务器端)在这里,我无法修改它(它是一个 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));
}

我发现了几个 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;
}

没有返回相同的结果(PHP!= ObjC) 。

我使用 ObjC 实现将摘要长度更改为 32(结果与 PHP 实现的长度相同),将密钥长度更改为 64(对应于第一个 str_pad),但结果总是不同。

有人可以告诉我如何在 Objective-C 中得到相同的结果吗?

编辑:由于 ObjC 中的 2 个实现返回相同的结果,因此这里只有一个有用。

I have to implement the HMAC MD5 in my iPhone app. The PHP version of the algorithm (implemented server side for verification) is here and I can't modify it (it's an 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));
}

I found a couple of objective-C implementation :

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

Didn't return the same results (PHP != ObjC).

I played with ObjC implementations changing the digest length to 32 (result then has the same length than PHP implementation), the key length to 64 (corresponding to the first str_pad) but the results are always differents.

Can someone tell me how to have the same result in Objective-C ??

Edit: since the 2 implementations in ObjC return the same result only one is useful here..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

非要怀念 2024-08-16 05:09:57

根据我之前的回答,PHP 代码实现了 HMAC 算法的非标准变体。这个 Objective C 代码应该模仿它。我在 Mac OS X 10.4.11 上针对 PHP 代码测试了两种组合:

“短键”
“一些文本”

“这是一个很长的密钥。它超过了 64 个字节,这是重要的部分。”
“这是一些很长的文本。它超过了 64 个字节,这是重要的部分。”

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

As per my previous answer, the PHP code implements a non-standard variant of the HMAC algorithm. This Objective C code should imitate it. I tested it on Mac OS X 10.4.11 against the PHP code for two combinations:

"a short key"
"some text"

"This is a very long key. It is longer than 64 bytes, which is the important part."
"This is some very long text. It is longer than 64 bytes, which is the important part."

- (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;
}
我为君王 2024-08-16 05:09:57

首先,您的“ObjC2”使用的是 SHA1,而不是 MD5(这意味着您可能会遇到缓冲区溢出,因为 SHA1 是 20 字节,而 MD5 是 16 字节)。

其次,我认为您的 PHP HMAC 实现存在非标准变体。请注意,除了最后一次调用 md5() 之外的所有调用是如何用 pack("H*",...) 包装的?也就是说,除了 Base64 编码之前的最后一个之外的所有内容。我认为这意味着 PHP 代码是 Base64 编码数据的“可打印十六进制”表示(32 字节,每个 ASCII 中的十六进制数字)而不是“原始”值(16 字节)。

由于您无法更改 PHP 实现,因此您必须在 Objective C 中编写具有相同非标准变体的 HMAC 实现。

First, your “ObjC2” is using SHA1, not MD5 (this means you are probably getting a buffer overrun since SHA1 is 20 bytes, while MD5 is 16 bytes).

Second, I think there is a non-standard variation in your PHP HMAC implementation. Notice how all but the last invocations of md5() are wrapped with a pack("H*",…)? All but the last one right before Base64 encoding, that is. I think this means that the PHP code is Base64 encoding the 'printable hex' representation of the data (32 bytes, each a hex digit in ASCII) not the 'raw' value (16 bytes).

Since you cannot change the PHP implementation, you will have to write an HMAC implementation in Objective C that has this same non-standard variation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文