2009-11-21 45 views
47

如果我在亞馬遜S3上有現有文件,在不必下載文件的情況下獲取md5sum的最簡單方法是什麼?如何獲得亞馬遜S3上文件的md5sum

謝謝

+0

ETag頭是MD5,但不適用於多部分文件。以下是關於如何使用它的更多信息:http://stackoverflow.com/questions/6591047/etag-definition-changed-in-amazon-s3/31086810#31086810 – r03 2015-07-21 19:35:59

+0

考慮改變對這個問題的接受答案,因爲人誰不讀下面的評論和答案將被誤導。 – JLo 2016-05-17 15:41:04

回答

35

嗯......我想你可以看看ETag頭。 (在這種情況下,您可以使用HTTP HEAD方法而不是GET)。他們不太明確地說,但幾乎可以肯定,Amazon使用MD5散列作爲ETag。從PUT Object documentation(說不上來爲什麼他們不只是直截了當地說):

爲了確保數據不被損壞,在網絡上,使用Content-MD5標頭。當您使用Content-MD5標頭時,Amazon S3會根據提供的MD5值檢查對象。如果它們不匹配,則Amazon S3會返回錯誤。此外,您可以在將對象放入Amazon S3時計算MD5,並將返回的Etag與計算出的MD5值進行比較。

此外,SOAP methods讓您只請求元數據而不是數據本身。

+58

這個回答不再有效。 Etag也可以返回一些不同的東西,例如「08e1ef8708f6b9ba5f65596254f45111-1」 – 2011-09-01 15:03:01

+1

如果我使用s3cmd上傳,它會顯式設置ETag爲上傳文件的(正確)MD5校驗和。希望s3cmd也可以驗證通過'put'上傳的文件的校驗和(http://aws.amazon.com/articles/1904)。 – 2012-06-07 20:01:47

+0

@AdamMonsen我不認爲s3cmd會將ETag設置爲MD5,因爲在Web界面中,多部分上傳文件的ETag仍然顯示上面提到的內容中帶有短劃線的格式。算法如何計算ETag在[這個答案](http://stackoverflow.com/a/19304527/1132850)中解釋。我想s3cmd設置一個自定義標題來保存md5總和。 – PiQuer 2014-08-19 10:03:06

21

對於分段上傳,ETag似乎不是MD5(按照Gael Fraiteur的評論)。在這些情況下,它包含一個減號和一個數字的後綴。然而,即使是減號之前的位似乎也不是MD5,即使它與MD5的長度相同。後綴可能是上傳的零件數量?

+3

此後綴似乎只在文件較大(大於5GB)時纔會顯示。通過檢查我擁有的大量文件,看起來後綴代表上傳的部分數量。但是,第一部分似乎沒有與原始文件相同的md5散列。在計算這個散列時,亞馬遜必須爲每個部分摺疊一些額外的數據。我想知道該算法,以便我可以檢查一些文件。 – 2012-08-29 19:19:12

+2

哈希算法在這裏描述:http://stackoverflow.com/questions/6591047/etag-definition-changed-in-amazon-s3 – Nakedible 2014-09-04 22:02:35

0

這對我的作品。 在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; 
     } 
    } 

3

對於任何人誰花時間來搜索周圍找出爲什麼MD5不一樣的ETag的S3。

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

ETag AWS的文件說:

實體標記爲對象的哈希值。 ETag僅反映對象內容的變化,而不反映其元數據。 ETag可能是也可能不是對象數據的MD5摘要。不論它是取決於對象是如何創建的,以及如何,如下所述加密:由PUT物件,POST對象或複製操作創建

  • 對象,或通過AWS管理控制檯,並且是由SSE-S3或明文加密,具有ETags,它們是對象數據的MD5摘要。
  • 由PUT對象,POST對象或複製操作或通過AWS管理控制檯創建並由SSE-C或SSE-KMS加密的對象具有不是其對象數據的MD5摘要的ETags。
  • 如果通過分段上載或部分複製操作創建對象,則無論採用何種加密方法,ETag都不是MD5摘要。

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

0

這裏是代碼即可獲得MD5哈希按照2017年

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

註釋代碼是大多數人把它錯誤的將其更改爲十六進制

0

下面是從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 
}