在 Haxe 中为 AWS S3 REST 生成 Content-MD5

Posted

技术标签:

【中文标题】在 Haxe 中为 AWS S3 REST 生成 Content-MD5【英文标题】:Generating Content-MD5 for AWS S3 REST in Haxe 【发布时间】:2015-09-24 05:20:14 【问题描述】:

我正在尝试将 Content-MD5 标头添加到我在 Haxe 中对 AWS S3 的 REST 调用(编译为 php)。它是由

生成的
var contentMD5 = haxe.crypto.Base64.encode(haxe.io.Bytes.ofString(haxe.crypto.Md5.encode(_data)));

_data 在我的示例中是

<Delete><Object><Key>nathan/storage/72ENgrtnpA5VAoy7zEpzPRNEChN0TRGc</Key></Object><Object><Key>nathan/storage/7rlZZSJFvZ7AxUhQZsh4ufn9M2x8m1ae</Key></Object><Object><Key>nathan/storage/HN8NFlUnJiiGo7qlddvRrlGE6hPmWMnZ</Key></Object><Object><Key>nathan/storage/SFsZ8z63DswEVFJQJqmUwbenaWyfZ8zb</Key></Object><Object><Key>nathan/storage/YSYXXgYbSZixOKo27PL65ii6nCeiFesl</Key></Object></Delete>

我使用 AWS 签名版本 4(存储桶、签名和凭证缩短)发送到 AWS 的完整请求(用于多次删除调用,如此处 http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html 所述):

POST /?delete= HTTP/1.1
Host: mybucket.s3-eu-central-1.amazonaws.com
Content-Length: 392
x-amz-content-sha256: 53da469cb6fc9d0701a1c6ff98d48edd361cd8a90d8a290a2dd224b2681bf7fb
x-amz-date: 20150923T195117Z
Authorization: AWS4-HMAC-SHA256 Credential=zzzzz/20150923/eu-central-1/s3/aws4_request, SignedHeaders=content-md5;host;x-amz-date, Signature=xxxxx
Content-MD5: MDAzNDZmZjJiMGJkMDFkNzVjYzFiOGE4MzI5NTc0NGY=

<Delete><Object><Key>nathan/storage/72ENgrtnpA5VAoy7zEpzPRNEChN0TRGc</Key></Object><Object><Key>nathan/storage/7rlZZSJFvZ7AxUhQZsh4ufn9M2x8m1ae</Key></Object><Object><Key>nathan/storage/HN8NFlUnJiiGo7qlddvRrlGE6hPmWMnZ</Key></Object><Object><Key>nathan/storage/SFsZ8z63DswEVFJQJqmUwbenaWyfZ8zb</Key></Object><Object><Key>nathan/storage/YSYXXgYbSZixOKo27PL65ii6nCeiFesl</Key></Object></Delete>

响应如下(RequestId和HostId缩写)

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>InvalidDigest</Code><Message>The Content-MD5 you specified was invalid.</Message><Content-MD5>MDAzNDZmZjJiMGJkMDFkNzVjYzFiOGE4MzI5NTc0NGY=</Content-MD5><RequestId>rrrrrr</RequestId><HostId>ccccccc</HostId></Error>

在我看来,生成的 MD5 是正确的。我用其他工具验证了这个值。另外,请注意x-amz-content-sha256 基于相同的_data,AWS 在我之前的(非删除)调用中接受了该标头。

我在这里缺少什么?为什么我的 MD5 值与 AWS 生成的不同?

【问题讨论】:

【参考方案1】:

你很亲密。

问题来了:

一个 md5 哈希在二进制表示中是 16 个字节,在十六进制表示中是 32 个字符,在 base64 中是 24 个字符(包括填充)。

你的大约是两倍长。您似乎正在使用 32 个字符的十六进制 md5 和 base64 编码 that,从而产生大约 44 个字符的 base64 字符串,而不仅仅是编码二进制形式。

请注意,尽管我断言您正在编码 32 个初始字节而不是 16,但输出的长度 44 与 24 并不是两倍。这是预期的,因为 base64 output_bytes = ceil(input_bytes/3) * 4.

我的专长是 S3 API——不是我从未使用过的 haxe——所以上面的内容几乎可以肯定是正确的,但下面是胡乱猜测。

var contentMD5 = haxe.crypto.Base64.encode(haxe.crypto.Md5.make(_data));

【讨论】:

非常感谢迈克尔,非常全面。您建议的 Haxe 代码不起作用,但它使我找到了正确的解决方案:var contentMD5 = haxe.crypto.Base64.encode(haxe.crypto.Md5.make(haxe.io.Bytes.ofString(_data)));【参考方案2】:

任何想要在 java 中执行此操作的人都可以使用此代码

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Base64;
public class GenerateMD5 
public static void main(String args[]) throws Exception
    String s = "<CORSConfiguration> <CORSRule> <AllowedOrigin>http://www.example.com</AllowedOrigin> <AllowedMethod>PUT</AllowedMethod> <AllowedMethod>POST</AllowedMethod> <AllowedMethod>DELETE</AllowedMethod> <AllowedHeader>*</AllowedHeader> <MaxAgeSeconds>3000</MaxAgeSeconds> </CORSRule> <CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <AllowedHeader>*</AllowedHeader> <MaxAgeSeconds>3000</MaxAgeSeconds> </CORSRule> </CORSConfiguration>";

        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(s.getBytes());
        byte[] digest = md.digest();
        StringBuffer sb = new StringBuffer();
        /*for (byte b : digest) 
            sb.append(String.format("%02x", b & 0xff));
        */
        System.out.println(sb.toString());
        StringBuffer sbi = new StringBuffer();
        byte [] bytes = Base64.encodeBase64(digest);
        String finalString = new String(bytes);
        System.out.println(finalString);
    

注释代码是大多数人错误地将其更改为十六进制的地方

【讨论】:

以上是关于在 Haxe 中为 AWS S3 REST 生成 Content-MD5的主要内容,如果未能解决你的问题,请参考以下文章

如何在AWS中为自己的S3托管站点添加SSL/TSL证书(https)

如何将 S3 用作静态网页和 EC2 作为 REST API 一起使用? (AWS)

通过 ACM 和负载均衡器为 aws Nodejs 弹性 beanstalk 设置了 HTTPS,我如何在 s3 存储桶中为 Angular 设置 HTTPS

基于云和 REST API 的记录和存储到 Google 存储桶或 AWS S3

带有 Android Retrofit V2 库的 AWS S3 Rest API,上传的图像已损坏

AWS 无法为云端 CNAME 指定没有子域的路由 53 记录