2016-05-15 54 views
1

我正在嘗試創建一個簡單的表單,以使用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格式可能會讓事情變得糟糕,但無論我如何格式化它(即新行,轉義等),我似乎無法使其工作。

回答

1

解碼亞馬遜的和你的,他們是不一樣的,主要是格式。簡單的格式差異會導致不同的簽名散列。

在你的情況下,你需要在每行的末尾添加換行符。

亞馬遜

 
{ "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" } 
    ] 
} 

此致:

 
{ "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" } ]} 
'
+0

您好,感謝您的快速反應。我也在最後用新行生成了編碼,但是我得到了這個比較: https://www.diffnow.com/?report=v5uzl 解碼後,我生成的base64和amazon的結果相同! –

+0

在diffnow的版本中,行結尾有差異,Amazon有兩個字符:CR,LF(0x0d,0x0a)和Java有一個字符:LF(0x0a)。這就是爲什麼需要使用十六進制的問題時,它永遠不會存在。DiffNow忽略了行結束問題,忽略了「額外」行結尾字節,但是SHA使用它們全部。對不起,十六進制可能是舊學校,但對於編碼和密碼學等低級問題來說,它仍然存在並且是必需的。哎呀,即使我的妻子讀hex,她也不是程序員。 – zaph

+0

十六進制根本就不是老派!你說的是絕對正確的!再次感謝! –