1
votes

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:

  1. Beginning with an empty string (""), append a forward slash (/), followed by the name of the account that owns the resource being accessed.

  2. 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

1
What's the use case for this? Every user of this iPhone app owns a storage account? The reason most people don't access storage directly from the phone is there's no security model for doing this without leaking the key to the client (and thus giving everyone full access to delete all your data, etc.).user94559
I was assuming that taking my key and encrypting it before sending the auth over the wire was security enough. Are you implying that there is not a secure model in the REST specification for azure table storage specified in my link above? How would a user extract the key?Scott Chamberlin
@ScottChamberlin thanks a lot for this question.i followed your same method and im also getting the same error.Can you please tell me how to solve that.Hope for your help.Thanks in advancesuji

1 Answers

0
votes

Smarx explained the best practice to me on the Azure forum. Here is what he wrote: There are two secure ways to access storage from the client:

1.Use Shared Access Signatures with blobs. Server-side, you can generate the signature (basically a signed URL), and that signature is limited in scope (maybe to a particular blob, particular permissions, and a limited amount of time). 2.Only access a web service from the client, and have the web service access storage. In both cases, there's a server in between, much like in a web app. (The browser never talks to your SQL database... it talks to your website, which then talks to the database.)