使用MD5哈希上传流导致“您指定的Content-MD5无效”

时间:2013-11-09 15:53:49

标签: c# hash amazon-web-services amazon-s3 md5

我正在使用Amazon S3开展实施。我使用Amazon C# SDK,我尝试使用putObject方法上传创建的ZIP文件。

当我上传文件时,出现以下错误:

{Amazon.S3.AmazonS3Exception: The Content-MD5 you specified was invalid

我生成了一个精细且有效的内存流,我可以毫无错误地将其上传到Amazon S3。但是,当我提供以下行时,它会给我带来问题:

request.MD5Digest = md5;

我是否证明了MD5的正确方法?我的MD5代是否正确?或者还有其他错误吗?

对我的上传代码的要求

Once the Zip file has been created and you have calculated an MD5 sum value of that file, you should 
transfer the file to the AWS S3 bucket identified in the S3Access XML. 
Transfer the file using the AmazonS3, PutObjectRequest and TransferManagerclasses. 
Ensure the following meta data attributes are included via adding an ObjectMetaDataclass instance to the
PutObjectRequest:
• MD5Sum (via setContentMD5)
• Mime ContentType (setContentType)

我的上传代码

client.PutObject()给出错误:

public void UploadFile(string bucketName, Stream uploadFileStream, string remoteFileName, string md5)
        {
            using (client = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKeyID, secretAccessKeyID, config))
            {
                try
                {
                    StringBuilder stringResp = new StringBuilder();

                    PutObjectRequest request = new PutObjectRequest();
                   // request.MD5Digest = md5;
                    request.BucketName = bucketName;
                    request.InputStream = uploadFileStream;
                    request.Key = remoteFileName;
                    request.MD5Digest = md5;

                    using (S3Response response = client.PutObject(request))
                    {
                        WebHeaderCollection headers = response.Headers;
                        foreach (string key in headers.Keys)
                        {
                            stringResp.AppendLine(string.Format("Key: {0}, value: {1}", key,headers.Get(key).ToString()));
                            //log headers ("Response Header: {0}, Value: {1}", key, headers.Get(key));
                        }
                    }
                }
                catch (AmazonS3Exception amazonS3Exception)
                {
                    if (amazonS3Exception.ErrorCode != null && (amazonS3Exception.ErrorCode.Equals("InvalidAccessKeyId") || amazonS3Exception.ErrorCode.Equals("InvalidSecurity")))
                    {
                        //log exception - ("Please check the provided AWS Credentials.");
                    }
                    else
                    {
                        //log exception -("An error occurred with the message '{0}' when writing an object", amazonS3Exception.Message);
                    }
                }
            }
        }

整体方法

我的处理方法(查看整体流程)。抱歉,代码的当前状态是伪代码,而不是生产代码:

 public void Process(List<Order> order)
    {
        var zipName = UserName + "-" + DateTime.Now.ToString("yy-MM-dd-hhmmss") + ".zip";
        var zipPath = HttpContext.Current.Server.MapPath("~/Content/zip-fulfillment/" + zipName);

        CreateZip(order, zipPath);


        var s3 = GetS3Access();

        var amazonService = new AmazonS3Service(s3.keyid, s3.secretkey, "s3.amazonaws.com");
        var fileStream = new MemoryStream(HelperMethods.GetBytes(zipPath));
        var md5val = HelperMethods.GetMD5HashFromStream(fileStream);
        fileStream.Position = 0;
        amazonService.UploadFile(s3.bucket, fileStream, zipName, md5val);

        var sqsDoc = DeliveryXml(md5val, s3.bucket, "Test job");

        amazonService.SendSQSMessage(sqsDoc.ToString(), s3.postqueue);
    }

MD5哈希方法:

此方法用于从我的内存流创建MD5哈希:

    public static string GetMD5HashFromStream(Stream stream)
    {

        MD5 md5 = new MD5CryptoServiceProvider();
        byte[] retVal = md5.ComputeHash(stream);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < retVal.Length; i++)
        {
            sb.Append(retVal[i].ToString("x2"));
        }
        return sb.ToString();
    }

修改

在整个方法中添加了fileStream.Position = 0。但问题仍然完全相同。

2 个答案:

答案 0 :(得分:10)

我怀疑问题可能是在计算流的哈希之后,流被留在数据的 end ...所以当以后从其中读取任何内容时,会出现&#39 ;没有数据。尝试在调用GetMD5HashFromStream

后添加此内容
fileStream.Position = 0;

这将&#34;倒带&#34;流,这样你就可以再次阅读它。

编辑:看过文档,虽然以上是 问题,但它并不是唯一的问题。目前,您附加了MD5哈希的十六进制表示形式 - 但documentation个状态:

  

Content-MD5:消息的base64编码的128位MD5摘要

注意&#34; base64编码&#34;部分。因此,您希望将MD5代码更改为:

public static string GetMD5HashFromStream(Stream stream)
{
    using (MD5 md5 = MD5.Create())
    {
        byte[] hash = md5.ComputeHash(stream);
        return Convert.ToBase64String(hash);
    }
}

答案 1 :(得分:0)

如果您使用的是AWS .NET SDK,则实际上可以使用自己的实用程序类来执行此操作。看看这个测试https://github.com/aws/aws-sdk-net/blob/f2823205eba5e5cfcaa7a98ce59bfda3f9749a0e/sdk/test/Services/S3/IntegrationTests/ObjectLockConfigurationTests.cs并搜索“ MD5Digest”,您会看到这种情况

var putObjectRequest = new PutObjectRequest()
{
    BucketName = bucketName,
    Key = key,
    ContentBody = content,
    MD5Digest = AmazonS3Util.GenerateChecksumForContent(content, true),
};

if (retainUntilDate.HasValue)
{
    putObjectRequest.ObjectLockMode = ObjectLockMode.Governance;
    putObjectRequest.ObjectLockRetainUntilDate = retainUntilDate.Value;
}