我必须在我的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个实现返回相同的结果,因此只有一个在这里有用..
答案 0 :(得分:4)
根据我之前的回答,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;
}
答案 1 :(得分:2)
首先,你的“ObjC2”使用的是SHA1,而不是MD5(这意味着你可能会得到一个缓冲区溢出,因为SHA1是20个字节,而MD5是16个字节)。
其次,我认为您的PHP HMAC实现存在非标准差异。请注意除了md5()的最后一次调用之外的所有调用都是用包(“H *”,...)包装的?除了Base64编码之前的最后一个,就是。我认为这意味着PHP代码是Base64编码数据的'可打印十六进制'表示(32个字节,每个都是ASCII中的十六进制数字)而不是'原始'值(16个字节)。
由于您无法更改PHP实现,因此您必须在Objective C中编写具有相同非标准变体的HMAC实现。