The Amazon S3 proposal for uploading via POST describes how to assemble a policy document that can be used to create a time-sensitive signature. The obvious advantage to this method is that you don't have to worry about someone stealing your secret AWS key or uploading random files without your permission.
Here is the example policy document from the proposal:
{ "expiration": "2007-12-01T12:00:00.000Z", "conditions": [ {"acl": "public-read" }, {"bucket": "johnsmith" }, ["starts-with", "$key", "user/eric/"], ["content-length-range", 2048, 20971520] ] }This Policy document is Base64 encoded and the Signature is the HMAC of the Base64 encoding.
The application I am developing at work requires this signed policy method of uploading files to S3, however I needed to do it with PHP4 and preferably without any extra PEAR packages. This posed somewhat of a challenge, as all the tutorials I found on the web explained how to sign the policy using the PEAR Crypt_HMAC package or some feature of PHP5.
I eventually figured it out, and I'm here to show you how. The two functions used were found on the web (I don't remember exactly where) and worked perfectly for my situation.
(Note: I had a lot of trouble saving the contents of the following code in WordPress due to some Apache mod_security settings configured on my server.)
/*
* Calculate HMAC-SHA1 according to RFC2104
* See http://www.faqs.org/rfcs/rfc2104.html
*/
function hmacsha1($key,$data) {
$blocksize=64;
$hashfunc='sha1';
if (strlen($key)>$blocksize)
$key=pack('H*', $hashfunc($key));
$key=str_pad($key,$blocksize,chr(0x00));
$ipad=str_repeat(chr(0x36),$blocksize);
$opad=str_repeat(chr(0x5c),$blocksize);
$hmac = pack(
'H*',$hashfunc(
($key^$opad).pack(
'H*',$hashfunc(
($key^$ipad).$data
)
)
)
);
return bin2hex($hmac);
}
/*
* Used to encode a field for Amazon Auth
* (taken from the Amazon S3 PHP example library)
*/
function hex2b64($str)
{
$raw = '';
for ($i=0; $i < strlen($str); $i+=2)
{
$raw .= chr(hexdec(substr($str, $i, 2)));
}
return base64_encode($raw);
}
/* Create the Amazon S3 Policy that needs to be signed */
$policy = '{ "expiration": "2007-12-01T12:00:00.000Z",
"conditions": [
{"acl": "public-read" },
{"bucket": "johnsmith" },
["starts-with", "$key", "user/eric/"],
["content-length-range", 2048, 20971520]
]';
/*
* Base64 encode the Policy Document and then
* create HMAC SHA-1 signature of the base64 encoded policy
* using the secret key. Finally, encode it for Amazon Authentication.
*/
$base64_policy = base64_encode($policy);
$signature = hex2b64(hmacsha1($secretkey, $base64_policy));
That's it! This method doesn't require PHP5 and doesn't require any additional PEAR packages.
Excellent piece of code!!!
Verry good for people not interested in libs. Also a good basis for further dev on html post s3 tricks.
Thanks Lex!
As much as I love some of the libs out there, I always try to accomplish things without adding extra bloat.
You are my f*ing hero! I spent a lot of time trying to generate signatures using hash_hmac(‘sha1’) from the hash extension for php and it does NOT produce proper results (according to amazon). Thank you!
Thanks Sam!
I too tried the hash_hmac(‘sha1’) from the has extension and wasn’t able to get it working with Amazon’s stuff, but I never figured out why.
MOUHAHAHAH . This is what i have been lookin for …. .
Yes i tryied to combine javascript code with SHA1.js and php . But Didnt generate the matching signature . But this is just great . Thx to you.
Glad to help, John!
Hi Raam,
excellent code! Thank’s a lot!
I think, there is a missing } at the end of you $policy
You’re most welcome, Daniel! Thanks for pointing out the missing “}”! 🙂
Hey man!!!! it’s works
I’m really happy for that !!!!
Thanks man 😀
You’re most welcome! Glad I could help! 🙂
Probably saved me hours of work. Thanks!
Raam Dev, are you indian?
Hi Ammad, no, I’m not Indian. My parents follow Vedic teachings and they gave me an Indian name when I was born. 🙂
Thank you Raam Dev, excellent piece of code for Amazon S3.Can you help me generate a policy and signature for Google cloud storage even by some php code.
Hi Zohera,
Glad to hear the code helped! I haven’t worked with Google cloud storage at all, so unfortunately I can’t help.
How to allow only specific email address to view the file uploaded in amazon s3 which is set private.
for example user1 has added a file in amazon s3,he wants only [email protected] to view the file.
Is it possile to acheive it through php code?
I haven’t done anything with Amazon S3 in a while, so I’m really not sure. I recommend posting your question over on Stackoverflow. They’ve got a great community and lots of very knowledgable people!
What is [“starts-with”, “$key”, “user/eric/”],
and $key
It means that “the key must start with the prefix user/eric/.” Please see the Amazon Access Control section for more info.
Nice and thank you. I ran from the command line to use in a non-php implementation. Just added and populated the $secretkey variable, a simple policy and print $base64_policy;
print ‘##############’;
print $secretkey;
You’re most welcome, Mike! 🙂
How this line
$signature = hex2b64(hmacsha1($secretkey, $base64_policy));
is getting the value of $secret_key?
You’ll need to define
$secretkey
so that it contains a valid secret key when being passed to thehmacsha1()
function. I hope this helps!