Answered by:
<signature> is not the same as any computed signature

-
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)
Question
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
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.
-
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?
葛先生 :) -
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-AliveThe 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; }
-
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.
葛先生 :) -
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
-
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