I would like to sign a request with HMAC SHA512, but I seem to mess up encoding and decoding from and to NSData and NSString. I desperately tried to figure out what is wrong, but I just don't seem to get it right.
function hmac_512(msg, sec) {
sec = Base64Decode(sec);
result = hmac(msg, sec, sha512);
return Base64Encode(result);
}
secret = "7pgj8Dm6";
message = "Test\0Message";
result = hmac_512(message, secret);
if (result == "69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==")
print("Success!");
else
printf("Error: %s", result);
+(void)doSomeMagic{
NSString *message = @"Test\0Message";
NSString *signedRequest = [self signRequestForParameterString:message];
//checking against CORRECT (from JAVA equivalent) signed request
if ([signedRequest isEqualToString:@"69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==" ])
NSLog(@"Success!");
else
NSLog(@"Error!");
}
Here is the signing method:
+(NSString *)signRequestForParameterString:(NSString*)paramStr{
NSString *secret = @"7pgj8Dm6";
// secret is base64 encoded, so I decode it
NSData *decodedSecret = [secret base64DecodedData];
NSString *decodedSecretString = [NSString stringWithUTF8String:[decodedSecret bytes]];
NSData *data = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *dataString = [NSString stringWithUTF8String:[data bytes]];
return [self generateHMACSHA512Hash:decodedSecretString data:dataString];
}
Here is the hashing function:
+(NSString *)generateHMACSHA512Hash:(NSString *)key data:(NSString *)data{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC
length:sizeof(cHMAC)];
NSString *hash = [HMAC base64EncodedString];
return hash;
}
I am pretty sure it is due to the encoding of the strings (decodedSecretString and dataString). decodedSecretString
(decoded base64) after decoding is encoded in ASCII. However, when I call the hashing method, I encode it in ascii again, which will result in a null error. Everything is confusing me right now.
Your secret doesn't decode to a valid UTF-8 string, and Java allows NUL bytes in strings, but when you're converting "Test\0Message" to a C string and using strlen, its length is 4.
Something like this should work:
+(NSString *)signRequestForParameterString:(NSString*)paramStr{
NSString *secret = @"7pgj8Dm6";
NSData *data = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
return [self generateHMACSHA512Hash:[secret base64DecodedData] data:data];
}
+(NSString *)generateHMACSHA512Hash:(NSData *)key data:(NSData *)data{
unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, key.bytes, key.length, data.bytes, data.length, cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
return [HMAC base64EncodedString];
}