Amazon S3 Policy Signing in Java

For some reason, I'm struggling with signing generation for my Amazon S3 boot policy. I swear it worked for me at some point, but no more. Any help is appreciated. I need a fresh set of eyes.

Compared to Amazon S3 Signature Tester , I don’t get the same signature. However, when I directly use the signature coming out of this tool, everything works fine. So the problem is definitely in my signing process. In addition, the "String to be signed", decoded in hexadecimal, exits from this tool, is identical to my input policy, signed.

AWS docs says the process of creating a policy signature should look like this:

  • Policy encoding using UTF-8.
  • Encode these UTF-8 bytes with Base64.
  • Sign the policy using the private access key using the HMAC SHA-1.
  • Encode SHA-1 signature with Base64.

It seems quite straightforward. The only place for ambiguity can be at No. 3. AWS docs show a sample fragment for generating HMAC-SHA1 , and this is consistent with other Java cryptography examples I've seen.

I am using v1.6 to implement Apache Commons Base64. My signing code basically looks like this:

import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; /* ... */ private static final String UTF8 = "UTF-8"; private static final String HMACSHA1 = "HmacSHA1"; public static String sign(String secret, String data) { byte[] dataBytes = data.getBytes(UTF8); byte[] secretBytes = secret.getBytes(UTF8); SecretKeySpec signingKey = new SecretKeySpec(secretBytes, HMACSHA1); Mac mac = Mac.getInstance(HMACSHA1); mac.init(signingKey); byte[] signature = mac.doFinal(dataBytes); return Base64.encodeBase64String(signature); } 

And then my use of this signing is as follows:

 String signature = sign( /* AWS Secret Access Key copied directly out of the AWS Console */, /* policy properly serialized as JSON */); 
+6
source share
3 answers

Ok, I found it. Apparently, today I successfully skipped step number 2. I encoded the JSON policy as Base64, but then I directly sign the JSON string, not the Base64 string.

Step # 3 should probably be changed to "Sign Base64 policy using secret key using HMAC SHA-1".

I think I will leave this in case anyone else encounters a similar problem.

+5
source

Now this procedure is officially supported. http://aws.amazon.com/articles/1434

 import sun.misc.BASE64Encoder; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; String policy = (new BASE64Encoder()).encode( policy_document.getBytes("UTF-8")).replaceAll("\n","").replaceAll("\r",""); Mac hmac = Mac.getInstance("HmacSHA1"); hmac.init(new SecretKeySpec( aws_secret_key.getBytes("UTF-8"), "HmacSHA1")); String signature = (new BASE64Encoder()).encode( hmac.doFinal(policy.getBytes("UTF-8"))) .replaceAll("\n", ""); 

* Beware of the window implementation for this example, since some found problem was found there from message comments and a solution to the problem.

The result can be checked by this http://s3.amazonaws.com/doc/s3-example-code/post/post_sample.html

However, some said that this "org.apache.commons.codec.binary.Base64" is better because of this. http://www.asgarli.net/2011/03/replacing-sunmiscbase64encoder-and.html

+3
source
 String policy_document = "{\"expiration\": \"2009-01-01T00:00:00Z\"," + "\"conditions\": [" + "{\"bucket\": \"s3-bucket\"}," + "[\"starts-with\", \"$key\", \"uploads/\"]," + "{\"acl\": \"private\"}," + "{\"success_action_redirect\": \"http://localhost/\"}," + "[\"starts-with\", \"$Content-Type\", \"\"]," + "[\"content-length-range\", 0, 1048576]" + "]" + "}"; // Calculate policy and signature values from the given policy document and AWS credentials. String policy = new String( Base64.encodeBase64(policy_document.getBytes("UTF-8")), "ASCII"); Mac hmac = Mac.getInstance("HmacSHA1"); hmac.init(new SecretKeySpec( aws_secret_key.getBytes("UTF-8"), "HmacSHA1")); String signature = new String( Base64.encodeBase64(hmac.doFinal(policy.getBytes("UTF-8"))), "ASCII"); 
-1
source

Source: https://habr.com/ru/post/905246/


All Articles