我正在尝试创建一个简单的表单,以使用AWS签名V4直接从我的浏览器将对象发布到S3中的存储桶。亚马逊AWS签名V4 Java给出错误的编码
我使用Java为预签名表单生成策略和签名值。现在,我只想测试它的工作原理,所以我不介意这是一个手动签名生成过程。
我的Java代码如下
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class Lala {
static String policy_document = "{ \"expiration\": \"2015-12-30T12:00:00.000Z\"," +
" \"conditions\": [" +
" {\"bucket\": \"sigv4examplebucket\"}," +
" [\"starts-with\", \"$key\", \"user/user1/\"]," +
" {\"acl\": \"public-read\"}," +
" {\"success_action_redirect\": \"http://sigv4examplebucket.s3.amazonaws.com/successful_upload.html\"}," +
" [\"starts-with\", \"$Content-Type\", \"image/\"]," +
" {\"x-amz-meta-uuid\": \"14365123651274\"}," +
" {\"x-amz-server-side-encryption\": \"AES256\"}," +
" [\"starts-with\", \"$x-amz-meta-tag\", \"\"]," +
" {\"x-amz-credential\": \"AKIAIOSFODNN7EXAMPLE/20151229/us-east-1/s3/aws4_request\"}," +
" {\"x-amz-algorithm\": \"AWS4-HMAC-SHA256\"}," +
" {\"x-amz-date\": \"20151229T000000Z\" }" +
" ]" +
"}";
static String secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
public static void main(String[] args) throws Exception {
// Create a policy using UTF-8 encoding.
byte[] utf8_policy = policy_document.getBytes("UTF-8");
// Convert the UTF-8-encoded policy bytes to Base64. The result is the StringToSign.
String base64_policy = new String(Base64.encodeBase64(utf8_policy));
// Create a signing key.
byte[] signing_key = getSignatureKey(secret_key , "20151229", "us-east-1", "s3");
// Use the signing key to sign the StringToSign using HMAC-SHA256 signing algorithm.
byte[] signature_bytes = HmacSHA256(base64_policy, signing_key);
String signature = Hex.encodeHexString(signature_bytes);
System.out.println(base64_policy);
System.out.println();
System.out.println(signature);
}
static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Exception {
byte[] kSecret = ("AWS4" + key).getBytes("UTF-8");
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return kSigning;
}
static byte[] HmacSHA256(String data, byte[] key) throws Exception {
String algorithm="HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes("UTF-8"));
}
}
的政策文件和访问/密钥对从亚马逊的例子here所有拍摄。
我的代码还给下面的Base64编码政策:
eyAiZXhwaXJhdGlvbiI6ICIyMDE1LTEyLTMwVDEyOjAwOjAwLjAwMFoiLCAgImNvbmRpdGlvbnMiOiBbICAgIHsiYnVja2V0IjogInNpZ3Y0ZXhhbXBsZWJ1Y2tldCJ9LCAgICBbInN0YXJ0cy13aXRoIiwgIiRrZXkiLCAidXNlci91c2VyMS8iXSwgICAgeyJhY2wiOiAicHVibGljLXJlYWQifSwgICAgeyJzdWNjZXNzX2FjdGlvbl9yZWRpcmVjdCI6ICJodHRwOi8vc2lndjRleGFtcGxlYnVja2V0LnMzLmFtYXpvbmF3cy5jb20vc3VjY2Vzc2Z1bF91cGxvYWQuaHRtbCJ9LCAgICBbInN0YXJ0cy13aXRoIiwgIiRDb250ZW50LVR5cGUiLCAiaW1hZ2UvIl0sICAgIHsieC1hbXotbWV0YS11dWlkIjogIjE0MzY1MTIzNjUxMjc0In0sICAgIHsieC1hbXotc2VydmVyLXNpZGUtZW5jcnlwdGlvbiI6ICJBRVMyNTYifSwgICAgWyJzdGFydHMtd2l0aCIsICIkeC1hbXotbWV0YS10YWciLCAiIl0sICAgIHsieC1hbXotY3JlZGVudGlhbCI6ICJBS0lBSU9TRk9 ETk43RVhBTVBMRS8yMDE1MTIyOS91cy1lYXN0LTEvczMvYXdzNF9yZXF1ZXN0In0sICAgIHsieC1hbXotYWxnb3JpdGhtIjogIkFXUzQtSE1BQy1TSEEyNTYifSwgICAgeyJ4LWFtei1kYXRlIjogIjIwMTUxMjI5VDAwMDAwMFoiIH0gIF19
和下面的签名为它
1df5972015a56d4fdef92944436b91ce1f39b5cc684dcce9f4dab74b82734e84
其是从由亚马逊在上面的链接提供的不同。
我错过了什么吗?我有一种感觉,即policy_document变量中的String格式可能会让事情变得糟糕,但无论我如何格式化它(即新行,转义等),我似乎无法使其工作。
您好,感谢您的快速反应。我也在最后用新行生成了编码,但是我得到了这个比较: https://www.diffnow.com/?report=v5uzl 解码后,我生成的base64和amazon的结果相同! –
在diffnow的版本中,行结尾有差异,Amazon有两个字符:CR,LF(0x0d,0x0a)和Java有一个字符:LF(0x0a)。这就是为什么需要使用十六进制的问题时,它永远不会存在。DiffNow忽略了行结束问题,忽略了“额外”行结尾字节,但是SHA使用它们全部。对不起,十六进制可能是旧学校,但对于编码和密码学等低级问题来说,它仍然存在并且是必需的。哎呀,即使我的妻子读hex,她也不是程序员。 – zaph
十六进制根本就不是老派!你说的是绝对正确的!再次感谢! –