none
<signature> is not the same as any computed signature

    Question

  • Hi guys, 

    I am having a hard time trying to just list containers from a storage service. 

    I am receiving this error message now: 

     

    The MAC signature found in the HTTP request 'yt5AmAfDQ9l+bg0iJBTeX3ctX1r9brdUcLv3ZZVTngo=' is not the same as any computed signature. Server used following string to sign: 'GET

    x-ms-date:Sat, 11 Sep 2010 07:15:21 GMT

    x-ms-version:2009-09-19

    /MYSTORAGEACCOUNT/

    comp:list'.</AuthenticationErrorDetail></Error>

     

    That's fair enough but the string I attempted to sign is exactly this: 

     

    GET

    x-ms-date:Sat, 11 Sep 2010 07:15:21 GMT

    x-ms-version:2009-09-19

    /MYSTORAGEACCOUNT/

    comp:list

     

    Or from the code: 

    NSString *stringToSign = [NSString stringWithFormat:@"GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:%@\nx-ms-version:2009-09-19\n/%@/\ncomp:list",

    currentDate,

    _serviceName];

     

    I am thinking there might be an issue with the signing of this string, my implementation looks like this: 

     

    + (NSString *) getSignatureForString:(NSString *)data withKey:(NSString *)key {

    unsigned char digest[CC_SHA256_DIGEST_LENGTH];

    char *keyCharPtr = strdup([key UTF8String]);

    char *dataCharPtr = strdup([data UTF8String]);

     

    CCHmacContext hctx;

    CCHmacInit(&hctx, kCCHmacAlgSHA256, keyCharPtr, strlen(keyCharPtr));

    CCHmacUpdate(&hctx, dataCharPtr, strlen(dataCharPtr));

    CCHmacFinal(&hctx, digest);

    NSData *encryptedStringData = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];

     

    free(keyCharPtr);

    free(dataCharPtr);

    [Base64 initialize];

    NSString *hash = [Base64 encode:encryptedStringData];

    return hash;

    }

     

     

    Any ideas? 


    葛先生 :)
    • Moved by DanielOdievich Tuesday, September 28, 2010 9:43 PM forum migration (From:Windows Azure)
    Saturday, September 11, 2010 7:26 AM

Answers

  • Hi there, 

    Just to keep you updated. 

    I had a look at the EC2 requirements as API calls are signed in a similar manner. I tried to reconcile all that, and went all the way to recreate a small program on Visual Studio to find out where the problem was. 

    It turned out that the HMACSHA256 constructor in C# is expecting the key to be base64-encoded. On ObjC, using the CCHmac* commands, it is expecting the key to be UTF8-encoded.

    Hope that helps! 


    葛先生 :)
    • Marked as answer by iug Monday, September 13, 2010 11:16 AM
    Monday, September 13, 2010 11:15 AM

All replies

  • I don't know anything about Objective C but my interest was piqued by seeing a non C# version of HMAC generation. A quick search comes across several variants of using Objective C for generating AWS signatures - such as here. All of them seen to use NSData rather than char * - so that might be a direction to go in.

    Saturday, September 11, 2010 5:33 PM
  • Hi Neil, 

    I have been trying few different implementations of the signature part. 

    I have a control signature that I use to see how the implementation changes the signature but so far, they all generate the same string. 

    For instance, if I use this: 

    NSString *test = @"GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Sun, 11 Oct 2009 21:49:13 GMT\nx-ms-version:2009-09-19\n/myaccount/myaccount/mycontainered\ncomp:metadata\nrestype:container\ntimeout:20";

    signature = [AzureCredentialFactory getSignatureForString:test withKey:@"vIM49SHcJDQhhjRmU2QutB9FSZUwJ9Qdrb6nq4TJVa60Qw2mDTWmBT78GbLt+gMJV6FbVbUWS7Hfg3+8WHESJw=="];

     

    Well, the signature will always be: uid7TeU7L9L7eeqDNoDAvLppUueNBqfO1y0xh8UWpjw= 

    Is that something that I can double check somewhere? 

     

     


    葛先生 :)
    Sunday, September 12, 2010 2:36 AM
  • The highlighted portion of the string to sign you used is probably constructed wrong:

    GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Sun, 11 Oct 2009 21:49:13 GMT\nx-ms-version:2009-09-19\n/myaccount/myaccount/mycontainered\ncomp:metadata\nrestype:container\ntimeout:20

    I understand this is from a documented example but the issue is that the duplication of myaccount is an artefact of development storage and is not used for cloud storage. As an aside, I have often found it easier to get the REST interface working directly against cloud storage because of little details like this - and that Fiddler is a bit easier to use with cloud storage. The above would only be valid were it:

    GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Sun, 11 Oct 2009 21:49:13 GMT\nx-ms-version:2009-09-19\n/devstoreaccount1/devstoreaccount1/mycontainered\ncomp:metadata\nrestype:container\ntimeout:20 

    The following is a Fiddler output from a List Containers request I made successfuly to development storage

    GET /devstoreaccount1/?comp=list HTTP/1.1
    x-ms-date: Sun, 12 Sep 2010 07:18:23 GMT
    x-ms-version: 2009-09-19
    Authorization: SharedKey devstoreaccount1:i8eGc7Yotrb6l6fbpeT7zowLToa6gkE5zF1u58oHo1I=
    Accept-Charset: UTF-8
    Accept: application/atom+xml,application/xml
    Host: 127.0.0.1:10000
    Connection: Keep-Alive

    The string to sign was:

    GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Sun, 12 Sep 2010 07:18:23 GMT\nx-ms-version:2009-09-19\n/devstoreaccount1/devstoreaccount1/\ncomp:list

    The generated signature was:

    i8eGc7Yotrb6l6fbpeT7zowLToa6gkE5zF1u58oHo1I=

    Since I used development storage the account and key were:

    account: devstoreaccount1
    key: Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==

    You should be able to regenerate the signature I got using these values and the specified string to sign.

    I realise it is not Objective C but I can successfuly regenerate the signature with the following:

    private String GenerateSignature()
    {
    	String canonicalizedString = "GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Sun, 12 Sep 2010 07:18:23 GMT\nx-ms-version:2009-09-19\n/devstoreaccount1/devstoreaccount1/\ncomp:list";
    	Byte[] key = Convert.FromBase64String("Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==");
    	String signature = string.Empty;
    
    	using (HMACSHA256 hmacSha256 = new HMACSHA256(key))
    	{
    		Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
    		signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
    	}
    
    	return signature;
    }
    
    

     

     

    Sunday, September 12, 2010 7:34 AM
  • Hi Neil, 

     

    I was only using the devstoreaccount1 string to validate the HMAC signature. As it appears, there is something wrong with my ObjC implementation of your "GenerateSignature()" method. I don't get the same signature for the same input strings...

    I will dig on that. 


    葛先生 :)
    Monday, September 13, 2010 8:50 AM
  • Hi there, 

    Just to keep you updated. 

    I had a look at the EC2 requirements as API calls are signed in a similar manner. I tried to reconcile all that, and went all the way to recreate a small program on Visual Studio to find out where the problem was. 

    It turned out that the HMACSHA256 constructor in C# is expecting the key to be base64-encoded. On ObjC, using the CCHmac* commands, it is expecting the key to be UTF8-encoded.

    Hope that helps! 


    葛先生 :)
    • Marked as answer by iug Monday, September 13, 2010 11:16 AM
    Monday, September 13, 2010 11:15 AM
  • I hit here when searching for the same error. I was writing the code in javascript (clientside) and using CryptoJS lib to build the authorization sharedkey. cryptolibJS expected the secretkey to be in utf8 encoded (not base64). hence, I need to decode it first to make the code work. Thanks iug for posting your findings and give me the lead for the issue.

    Posting the reply - it may help others!

    full listing of the code can be found here


    -sushil

    Thursday, March 21, 2013 12:56 PM