Question

I'm trying to create a base64 signature for a rest request using the HMAC-SHA1 algorithm. I'm specifically using the SinglePlatform API, and the steps are:

  1. Strip off the domain portion of the request, leaving only the path and the query:/locations/haru-7?client=YOUR_CLIENT_ID
  2. Retrieve your private key, which is encoded in a modified Base64 for URLs, and sign the URL above using the HMAC-SHA1 algorithm. You may need to decode the Signing Key into its original binary format. In many cryptographic libraries, the resulting signature will be in binary format.
  3. Encode the resulting binary signature using the modified Base64 for URLs to convert this signature into something that can be passed within a URL. Attach this signature to the URL with a sigparameter:

My current implementation is as follows:

    // Convert a modified Base64 key into Base64
NSString *modifiedKey = [SIGNING_KEY stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
modifiedKey = [modifiedKey stringByReplacingOccurrencesOfString:@"_" withString:@"/"];

// Decode the Base64 key
NSData *key = [NSData dataFromBase64String:modifiedKey];

// Construct a url with params
NSString *data = [NSString stringWithFormat:@"/locations/%@?client=%@", _id, CLIENT_ID];

// Convert key and data to c chars
const char *keyBytes = [key bytes];
const char *baseStringBytes = [data cStringUsingEncoding:NSUTF8StringEncoding];

unsigned char digestBytes[CC_SHA1_DIGEST_LENGTH];

CCHmacContext ctx;
CCHmacInit(&ctx, kCCHmacAlgSHA1, keyBytes, strlen(keyBytes));
CCHmacUpdate(&ctx, baseStringBytes, strlen(baseStringBytes));
CCHmacFinal(&ctx, digestBytes);

NSData *digestData = [NSData dataWithBytes:digestBytes length:CC_SHA1_DIGEST_LENGTH];

// Reconvert the into Base64 modified 
NSString *signingKey = [digestData base64EncodedString];
signingKey = [signingKey stringByReplacingOccurrencesOfString:@"+" withString:@"-"];
signingKey = [signingKey stringByReplacingOccurrencesOfString:@"/" withString:@"_"];

if ( [data hasSuffix:@"="] ) {
    [signingKey substringToIndex:[hassigningKeyh length]-1];
}

NSLog(@"Signing Key: %@", signingKey);

The signing key I originally received is modified Base64, which is why I am replacing the -+_/ characters. This implementation has returned the proper signature key, but not consistently.

Am I doing something blatantly wrong in converting Objective-C to C? Is there a better way to handle this?

My application is using ARC.

Was it helpful?

Solution

The issue was that I was C methods to determine the data length:

CCHmacContext ctx;
CCHmacInit(&ctx, kCCHmacAlgSHA1, keyBytes, strlen(keyBytes));
CCHmacUpdate(&ctx, baseStringBytes, strlen(baseStringBytes));
CCHmacFinal(&ctx, digestBytes);

It worked consistently when I used the NSString/NSData length methods:

CCHmacContext ctx;
CCHmacInit(&ctx, kCCHmacAlgSHA1, keyBytes, [key length]);
CCHmacUpdate(&ctx, baseStringBytes, [data length]);
CCHmacFinal(&ctx, digestBytes);

Edit:
As mentioned by Ivo Beckers in the comments, this can also be written as a single line:

CCHmac(kCCHmacAlgSHA1, keyBytes, strlen(keyBytes), baseStringBytes, strlen(baseStringBytes), digestBytes);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top