如何在亚马逊S3上获取文件的md5sum

如果我有Amazon S3上的现有文件,那么无需下载文件即可获得md5sum的最简单方法是什么?

谢谢

嗯…我想你可以看看ETag头。 (在这种情况下,您可以使用HTTP HEAD方法而不是GET)。他们不太明确地说,但几乎可以肯定,Amazon使用MD5散列作为ETag。 从PUT的对象文件 (不知道为什么他们不只是出来说出来):

为确保数据在networking上不被破坏,请使用Content-MD5头。 当您使用Content-MD5标头时,Amazon S3将根据提供的MD5值检查对象。 如果它们不匹配,则Amazon S3会返回错误。 此外,您可以在将对象放入Amazon S3时计算MD5,并将返回的Etag与计算出的MD5值进行比较。

而且, SOAP方法只允许您请求元数据而不是数据本身。

对于分段上传,ETag似乎不是MD5(按照Gael Fraiteur的评论)。 在这些情况下,它包含一个减号和一个数字的后缀。 然而,甚至在减号之前的位似乎也不是MD5,尽pipe它与MD5的长度相同。 后缀可能是上传的部分数量?

AWS的文档ETag说:

实体标签是对象的散列。 ETag仅反映对象内容的变化,而不反映其元数据。 ETag可能是也可能不是对象数据的MD5摘要。 不pipe它是否取决于如何创build对象以及如何对其进行encryption,如下所述:

  • 由PUT对象,POST对象或复制操作或通过AWSpipe理控制台创build并由SSE-S3或明文encryption的对象具有ETags,它们是对象数据的MD5摘要。
  • 由PUT对象,POST对象或复制操作或通过AWSpipe理控制台创build并由SSE-C或SSE-KMSencryption的对象具有不是其对象数据的MD5摘要的ETag。
  • 如果通过分段上传或部分复制操作创build对象,则不pipeencryption的方式如何,ETag都不是MD5摘要。

参考: http : //docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html

我已经交叉检查jets3t和pipe理控制台对上传文件的MD5sum,和ETag似乎等于MD5sum。 您可以在AWSpipe理控制台中查看文件的属性:

https://console.aws.amazon.com/s3/home

对于那些花时间四处搜寻的人来说,为什么在S3中md5与ETag不一样。

ETag会根据数据查找计算出来,然后concat所有的md5hash再次做md5哈希,并保留数据块的末尾。

这里是C#版本来生成哈希

  string etag = HashOf("file.txt",8); 

源代码

  private string HashOf(string filename,int chunkSizeInMb) { string returnMD5 = string.Empty; int chunkSize = chunkSizeInMb * 1024 * 1024; using (var crypto = new MD5CryptoServiceProvider()) { int hashLength = crypto.HashSize/8; using (var stream = File.OpenRead(filename)) { if (stream.Length > chunkSize) { int chunkCount = (int)Math.Ceiling((double)stream.Length/(double)chunkSize); byte[] hash = new byte[chunkCount*hashLength]; Stream hashStream = new MemoryStream(hash); long nByteLeftToRead = stream.Length; while (nByteLeftToRead > 0) { int nByteCurrentRead = (int)Math.Min(nByteLeftToRead, chunkSize); byte[] buffer = new byte[nByteCurrentRead]; nByteLeftToRead -= stream.Read(buffer, 0, nByteCurrentRead); byte[] tmpHash = crypto.ComputeHash(buffer); hashStream.Write(tmpHash, 0, hashLength); } returnMD5 = BitConverter.ToString(crypto.ComputeHash(hash)).Replace("-", string.Empty).ToLower()+"-"+ chunkCount; } else { returnMD5 = BitConverter.ToString(crypto.ComputeHash(stream)).Replace("-", string.Empty).ToLower(); } stream.Close(); } } return returnMD5; } 

这对我有用。 在PHP中,您可以使用以下方法比较本地文件和亚马逊文件之间的校验和:

 // get localfile md5 $checksum_local_file = md5_file ( '/home/file' ); // compare checksum between localfile and s3file public function compareChecksumFile($file_s3, $checksum_local_file) { $Connection = new AmazonS3 (); $bucket = amazon_bucket; $header = $Connection->get_object_headers( $bucket, $file_s3 ); // get header if (empty ( $header ) || ! is_object ( $header )) { throw new RuntimeException('checksum error'); } $head = $header->header; if (empty ( $head ) || !is_array($head)) { throw new RuntimeException('checksum error'); } // get etag (md5 amazon) $etag = $head['etag']; if (empty ( $etag )) { throw new RuntimeException('checksum error'); } // remove quotes $checksumS3 = str_replace('"', '', $etag); // compare md5 if ($checksum_local_file === $checksumS3) { return TRUE; } else { return FALSE; } } 

这里是根据2017年获得MD5哈希的代码

 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); } } 

评论代码是大多数人错误的地方把它改为hex

以下是从c#转换为PowerShell中的对象的S3 ETag的代码。

 function Get-ETag { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$Path, [Parameter(Mandatory=$true)] [int]$ChunkSizeInMb ) $returnMD5 = [string]::Empty [int]$chunkSize = $ChunkSizeInMb * [Math]::Pow(2, 20) $crypto = New-Object System.Security.Cryptography.MD5CryptoServiceProvider [int]$hashLength = $crypto.HashSize / 8 $stream = [System.IO.File]::OpenRead($Path) if($stream.Length -gt $chunkSize) { $chunkCount = [int][Math]::Ceiling([double]$stream.Length / [double]$chunkSize) [byte[]]$hash = New-Object byte[]($chunkCount * $hashLength) $hashStream = New-Object System.IO.MemoryStream(,$hash) [long]$numBytesLeftToRead = $stream.Length while($numBytesLeftToRead -gt 0) { $numBytesCurrentRead = [int][Math]::Min($numBytesLeftToRead, $chunkSize) $buffer = New-Object byte[] $numBytesCurrentRead $numBytesLeftToRead -= $stream.Read($buffer, 0, $numBytesCurrentRead) $tmpHash = $crypto.ComputeHash($buffer) $hashStream.Write($tmpHash, 0, $hashLength) } $returnMD5 = [System.BitConverter]::ToString($crypto.ComputeHash($hash)).Replace("-", "").ToLower() + "-" + $chunkCount } else { $returnMD5 = [System.BitConverter]::ToString($crypto.ComputeHash($stream)).Replace("-", "").ToLower() } $stream.Close() $returnMD5 }