So erhalten Sie die md5sum einer Datei auf Amazon S3


77

Wenn ich bereits Dateien auf Amazon S3 habe, wie kann ich die md5sum am einfachsten abrufen, ohne die Dateien herunterladen zu müssen?

Vielen Dank


1
Der ETag-Header ist MD5, jedoch nicht für mehrteilige Dateien. Hier ist mehr Infos, wie Sie es verwenden können: stackoverflow.com/questions/6591047/…
r03

2
Gibt es keine Möglichkeit, einen MD5 für ein S3-Objekt zu berechnen, ohne das gesamte Objekt abzurufen und lokal zu berechnen? Derzeit befasst sich keine der Antworten mit dieser sehr einfachen Frage und konzentriert sich stattdessen ausschließlich auf das ETag. Die meisten Antworten, die die Verwendung des ETag vorschlagen, geben sogar zu, dass es kein geeigneter Ersatz für ein berechnetes MD5 ist.
bsplosion

Antworten:


31

Die Dokumentation von AWS ETaglautet:

Das Entity-Tag ist ein Hash des Objekts. Das ETag spiegelt nur Änderungen am Inhalt eines Objekts wider, nicht dessen Metadaten. Das ETag kann ein MD5-Digest der Objektdaten sein oder nicht. Ob dies der Fall ist oder nicht, hängt davon ab, wie das Objekt erstellt und wie unten beschrieben verschlüsselt wurde:

  • Objekte, die vom PUT-Objekt-, POST-Objekt- oder Kopiervorgang oder über die AWS Management Console erstellt und mit SSE-S3 oder Klartext verschlüsselt wurden, verfügen über ETags, die einen MD5-Digest ihrer Objektdaten darstellen.
  • Objekte, die durch den Vorgang PUT-Objekt, POST-Objekt oder Kopieren oder über die AWS Management Console erstellt und von SSE-C oder SSE-KMS verschlüsselt wurden, verfügen über ETags, die keine MD5-Zusammenfassung ihrer Objektdaten darstellen.
  • Wenn ein Objekt entweder durch das Hochladen mehrerer Teile oder durch das Kopieren von Teilen erstellt wird, ist das ETag unabhängig von der Verschlüsselungsmethode kein MD5-Digest.

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


26

ETag scheint kein MD5 für mehrteilige Uploads zu sein (gemäß dem Kommentar von Gael Fraiteur). In diesen Fällen enthält es ein Suffix von Minus und eine Zahl. Selbst das Bit vor dem Minus scheint jedoch nicht das MD5 zu sein, obwohl es die gleiche Länge wie ein MD5 hat. Möglicherweise ist das Suffix die Anzahl der hochgeladenen Teile?


3
Dieses Suffix scheint nur zu erscheinen, wenn die Datei groß ist (größer als 5 GB). Wenn ich mir die wenigen Dateien ansehe, die groß sind, scheint das Suffix die Anzahl der hochgeladenen Teile darzustellen. Der erste Teil scheint jedoch nicht den gleichen md5-Hash wie die Originaldatei zu haben. Bei der Berechnung dieses Hashs muss amazon einige zusätzliche Daten für jedes Teil einklappen. Ich möchte den Algorithmus kennen, damit ich einige meiner Dateien überprüfen kann.
Broc.seib

2
Der Hash-Algorithmus wird hier beschrieben: stackoverflow.com/questions/6591047/…
Nakedible

@ broc.seib Ich sehe ein Suffix für Dateien, die viel kleiner sind, z. B. 18,3 MB. Ich frage mich, ob es davon abhängt, was zum Hochladen der Datei verwendet wird. Ich benutzeaws s3 cp ...
Mark

@Mark Die Antwort hier hat mehr Details: stackoverflow.com/a/19896823/516910
broc.seib

7

Im Folgenden kann ich die Prüfsumme für lokale Dateien mit s3 etag vergleichen. Ich habe Python benutzt

def md5_checksum(filename):
    m = hashlib.md5()
    with open(filename, 'rb') as f:
        for data in iter(lambda: f.read(1024 * 1024), b''):
            m.update(data)
   
    return m.hexdigest()


def etag_checksum(filename, chunk_size=8 * 1024 * 1024):
    md5s = []
    with open(filename, 'rb') as f:
        for data in iter(lambda: f.read(chunk_size), b''):
            md5s.append(hashlib.md5(data).digest())
    m = hashlib.md5(b"".join(md5s))
    print('{}-{}'.format(m.hexdigest(), len(md5s)))
    return '{}-{}'.format(m.hexdigest(), len(md5s))

def etag_compare(filename, etag):
    et = etag[1:-1] # strip quotes
    print('et',et)
    if '-' in et and et == etag_checksum(filename):
        return True
    if '-' not in et and et == md5_checksum(filename):
        return True
    return False


def main():   
    session = boto3.Session(
        aws_access_key_id=s3_accesskey,
        aws_secret_access_key=s3_secret
    )
    s3 = session.client('s3')
    obj_dict = s3.get_object(Bucket=bucket_name, Key=your_key)

    etag = (obj_dict['ETag'])
    print('etag', etag)
    
    validation = etag_compare(filename,etag)
    print(validation)
    etag_checksum(filename, chunk_size=8 * 1024 * 1024)
    return validation


Ist das your_keygleiche wie das filename?
Jason Liu

Es gibt verschiedene.
li xin

Bei der Verwendung der etag_checksumFunktion ist ein Problem mit Dateien aufgetreten, die kleiner als diese sind chunkt_size. Ein einfacher Test der Dateigröße ( os.path.getsize(filename) < chunk_size) hat dies behoben, falls auch jemand anderes dieses Problem hat. In diesem Fall lautet der Hashhashlib.md5(f.read())
KingBugAndTheCodeWizard

4

Für alle, die Zeit damit verbringen, sich umzuschauen, um herauszufinden, warum der md5 nicht mit ETag in S3 identisch ist.

ETag berechnet gegen das Einspannen von Daten und konzentriert alle md5hash, um md5-Hash erneut zu erstellen und die Anzahl der Chunks am Ende beizubehalten.

Hier ist die C # -Version zum Generieren von Hash

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

Quellcode

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

Dieser Code funktioniert bei mir für kleine Dateien. Große Dateien geben mir einen anderen Hash
Tono Nam

Wie groß ist die Datei?
Pitipong Guntawong

Wie erhalte ich die Blockgröße des mehrteiligen s3-Objektschlüssels?
Daniel

Abhängig von der Upload-Software. Sie können die
Blockgröße festlegen,

4

Dies ist eine sehr alte Frage, aber es fiel mir schwer, die folgenden Informationen zu finden, und dies ist einer der ersten Orte, die ich finden konnte. Deshalb wollte ich sie detailliert beschreiben, falls jemand sie benötigt.

ETag ist ein MD5. Für die hochgeladenen Multipart-Dateien wird der MD5 jedoch aus der Verkettung der MD5s jedes hochgeladenen Teils berechnet. Sie müssen den MD5 also nicht auf dem Server berechnen. Holen Sie sich einfach den ETag und es ist alles.

Wie @EmersonFarrugia in dieser Antwort sagte :

Angenommen, Sie haben eine 14-MB-Datei hochgeladen und Ihre Teilegröße beträgt 5 MB. Berechnen Sie 3 MD5-Prüfsummen für jedes Teil, dh die Prüfsumme der ersten 5 MB, der zweiten 5 MB und der letzten 4 MB. Nehmen Sie dann die Prüfsumme ihrer Verkettung. Da MD5-Prüfsummen hexadezimale Darstellungen von Binärdaten sind, stellen Sie sicher, dass Sie das MD5 der decodierten binären Verkettung und nicht der ASCII- oder UTF-8-codierten Verkettung verwenden. Wenn dies erledigt ist, fügen Sie einen Bindestrich und die Anzahl der Teile hinzu, um das ETag zu erhalten.

Das einzige andere, was Sie brauchen, ist das ETag und die Upload-Teilegröße. Das ETag hat jedoch das Suffix -NumberOfParts. So können Sie die Größe durch das Suffix teilen und die Teilegröße erhalten. 5 MB ist die minimale Teilegröße und der Standardwert. Die Teilegröße muss eine Ganzzahl sein, damit Sie nicht 7,25 MB pro Teilegröße erhalten können. Es sollte also einfach sein, Informationen zur Teilegröße zu erhalten.

Hier ist ein Skript, um dies in osx zu machen, mit einer Linux-Version in Kommentaren: https://gist.github.com/emersonf/7413337

Ich werde beide Skripte hier belassen, falls die obige Seite in Zukunft nicht mehr zugänglich ist:

Linux-Version:

#!/bin/bash
set -euo pipefail
if [ $# -ne 2 ]; then
    echo "Usage: $0 file partSizeInMb";
    exit 0;
fi
file=$1
if [ ! -f "$file" ]; then
    echo "Error: $file not found." 
    exit 1;
fi
partSizeInMb=$2
fileSizeInMb=$(du -m "$file" | cut -f 1)
parts=$((fileSizeInMb / partSizeInMb))
if [[ $((fileSizeInMb % partSizeInMb)) -gt 0 ]]; then
    parts=$((parts + 1));
fi
checksumFile=$(mktemp -t s3md5.XXXXXXXXXXXXX)
for (( part=0; part<$parts; part++ ))
do
    skip=$((partSizeInMb * part))
    $(dd bs=1M count=$partSizeInMb skip=$skip if="$file" 2> /dev/null | md5sum >> $checksumFile)
done
etag=$(echo $(xxd -r -p $checksumFile | md5sum)-$parts | sed 's/ --/-/')
echo -e "${1}\t${etag}"
rm $checksumFile

OSX-Version:

#!/bin/bash

if [ $# -ne 2 ]; then
    echo "Usage: $0 file partSizeInMb";
    exit 0;
fi

file=$1

if [ ! -f "$file" ]; then
    echo "Error: $file not found." 
    exit 1;
fi

partSizeInMb=$2
fileSizeInMb=$(du -m "$file" | cut -f 1)
parts=$((fileSizeInMb / partSizeInMb))
if [[ $((fileSizeInMb % partSizeInMb)) -gt 0 ]]; then
    parts=$((parts + 1));
fi

checksumFile=$(mktemp -t s3md5)

for (( part=0; part<$parts; part++ ))
do
    skip=$((partSizeInMb * part))
    $(dd bs=1m count=$partSizeInMb skip=$skip if="$file" 2>/dev/null | md5 >>$checksumFile)
done

echo $(xxd -r -p $checksumFile | md5)-$parts
rm $checksumFile

1

Ich habe festgestellt, dass s3cmd eine Option --list-md5 hat, die mit dem Befehl ls verwendet werden kann, z

s3cmd ls --list-md5 s3://bucket_of_mine/

Hoffe das hilft.


Dies ist praktisch, aber wie in mehreren anderen Antworten erwähnt, ist dies bei einigen Dateien nicht die tatsächliche MD5-Summe, sondern eine andere Art von Hash.
Ian Greenleaf Young

2
Ich habe den s3cmd-Quellcode überprüft und er speichert md5 beim Hochladen in Metadaten. Dieser Befehl druckt also nur md5 für Objekte, die mit s3cmd hochgeladen wurden, oder für Objekte, die in einem einzelnen Block hochgeladen wurden
ZAB

0

Ich habe jets3t und die Verwaltungskonsole mit der MD5sum der hochgeladenen Dateien verglichen, und ETag scheint MD5sum zu entsprechen. Sie können die Eigenschaften der Datei einfach in der AWS-Verwaltungskonsole anzeigen:

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


0

Am einfachsten ist es, die Prüfsumme selbst als Metadaten festzulegen, bevor Sie diese Dateien in Ihren Bucket hochladen:

ObjectMetadata md = new ObjectMetadata();
md.setContentMD5("foobar");
PutObjectRequest req = new PutObjectRequest(BUCKET, KEY, new File("/path/to/file")).withMetadata(md);
tm.upload(req).waitForUploadResult();

Jetzt können Sie auf diese Metadaten zugreifen, ohne die Datei herunterladen zu müssen:

ObjectMetadata md2 = s3Client.getObjectMetadata(BUCKET, KEY);
System.out.println(md.getContentMD5());

Quelle: https://github.com/aws/aws-sdk-java/issues/1711


-2

Das funktioniert bei mir. In PHP können Sie die Prüfsumme zwischen lokaler Datei und Amazon-Datei folgendermaßen vergleichen:



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


-2

Hier ist der Code zum Abrufen des S3 ETag für ein Objekt in PowerShell, das aus c # konvertiert wurde.

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
}

-3

Hier ist der Code, um MD5-Hash ab 2017 zu erhalten

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

Der kommentierte Code ist der Punkt, an dem die meisten Leute etwas falsch machen, wenn sie ihn in hexadezimal ändern

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.