I need help getting my headers correct for an azure table storage request from an iPhone app. I've been using these two posts to try and get the encryption of the key right but I'm still having trouble: iPhone and HMAC-SHA-1 encoding Objective-C sample code for HMAC-SHA1 The service is returning an error for my request: Server failed to authenticate the request with this error:
Make sure the value of Authorization header is formed correctly including the signature.
I am using the following code to make the request:
NSDate *now = [[NSDate alloc] init];
NSString *dateString = [self rfc1123String:now];
NSString *messageToSign = [NSString stringWithFormat:@"%@\n/%@/%@", dateString, AZURE_ACCOUNT_NAME, table];
[Base64 initialize];
//xxx in my code is my primary access shared key
NSString *key = @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [messageToSign cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
NSString *hash = [Base64 encode:HMAC];
NSLog(@"Encoded hash: %@", hash);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request addValue:[NSString stringWithFormat:@"SharedKeyLite %@:%@", AZURE_ACCOUNT_NAME, hash] forHTTPHeaderField:@"Authorization"];
[request addValue:dateString forHTTPHeaderField:@"x-ms-date"];
[request addValue:@"application/atom+xml, application/xml" forHTTPHeaderField:@"Accept"];
[request addValue:@"UTF-8" forHTTPHeaderField:@"Accept-Charset"];
NSLog(@"Headers: %@", [request allHTTPHeaderFields]);
NSLog(@"URL: %@", [[request URL] absoluteString]);
return request;
Which results in these headers being generated for the request:
Accept = "application/atom+xml, application/xml";
"Accept-Charset" = "UTF-8";
Authorization = "SharedKeyLite powderdayalarm:xwT1purDtREtxauVr6Bhvdz/2ObLh2J0lMw/prBBQBE=";
"X-Ms-Date" = "Fri, 05 Nov 2010 18:26:00 GMT";
The specification for the request is here: http://msdn.microsoft.com/en-us/library/dd179428.aspx Which refers to the following:
This format supports Shared Key and Shared Key Lite for all versions of the Table service, and Shared Key Lite for the 2009-09-19 version of the Blob and Queue services. This format is identical to that used with previous versions of the storage services. Construct the CanonicalizedResource string in this format as follows:
Beginning with an empty string (""), append a forward slash (/), followed by the name of the account that owns the resource being accessed.
Append the resource's encoded URI path. If the request URI addresses a component of the resource, append the appropriate query string. The query string should include the question mark and the comp parameter (for example, ?comp=metadata). No other parameters should be included on the query string.
Encoding the Signature
To encode the signature, call the HMAC-SHA256 algorithm on the UTF-8-encoded signature string and encode the result as Base64. Use the following format (shown as pseudocode): Copy
Signature=Base64(HMAC-SHA256(UTF8(StringToSign)))
I can't seem to get to the root of this one. And it doesn't seem like too many people are making azure requests form the iphone :).
Thanks Scott