IT박스

Amazon의 S3에서 파일의 md5sum을 가져 오는 방법

itboxs 2020. 11. 22. 19:15
반응형

Amazon의 S3에서 파일의 md5sum을 가져 오는 방법


Amazon의 S3에 기존 파일이있는 경우 파일을 다운로드하지 않고 md5sum을 얻는 가장 쉬운 방법은 무엇입니까?

감사


ETag는 멀티 파트 업로드의 경우 MD5가 아닌 것 같습니다 (Gael Fraiteur의 의견에 따라). 이 경우에는 접미사 마이너스와 숫자가 포함됩니다. 그러나 마이너스 앞의 비트조차 MD5와 길이가 같더라도 MD5가 아닌 것 같습니다. 아마도 접미사는 업로드 된 부품의 수입니까?


AWS의 설명서에 ETag따르면 다음과 같습니다.

엔티티 태그는 객체의 해시입니다. ETag는 메타 데이터가 아닌 개체의 내용에 대한 변경 사항 만 반영합니다. ETag는 개체 데이터의 MD5 다이제스트 일 수도 있고 아닐 수도 있습니다. 여부는 아래에 설명 된대로 객체가 생성 된 방법과 암호화 된 방법에 따라 다릅니다.

  • PUT 객체, POST 객체 또는 복사 작업 또는 AWS Management Console을 통해 생성되고 SSE-S3 또는 일반 텍스트로 암호화 된 객체에는 객체 데이터의 MD5 다이제스트 인 ETag가 있습니다.
  • PUT 객체, POST 객체 또는 복사 작업 또는 AWS Management Console을 통해 생성되고 SSE-C 또는 SSE-KMS로 암호화 된 객체에는 객체 데이터의 MD5 다이제스트가 아닌 ETag가 있습니다.
  • 멀티 파트 업로드 또는 파트 복사 작업으로 객체가 생성 된 경우 ETag는 암호화 방법에 관계없이 MD5 다이제스트가 아닙니다.

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


md5가 S3의 ETag와 동일하지 않은 이유를 찾기 위해 시간을 들여 주변을 검색하는 사람을 위해.

ETag는 데이터 척에 대해 계산하고 모든 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;
    }

s3cmd에는 ls 명령과 함께 사용할 수있는 --list-md5 옵션이 있습니다. 예 :

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

도움이 되었기를 바랍니다.


업로드 된 파일의 MD5sum에 대해 jets3t 및 관리 콘솔을 교차 확인했으며 ETag는 MD5sum과 동일한 것 같습니다. AWS 관리 콘솔에서 파일의 속성을 볼 수 있습니다.

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


가장 쉬운 방법은 이러한 파일을 버킷에 업로드하기 전에 체크섬을 메타 데이터로 직접 설정하는 것입니다.

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

이제 파일을 다운로드하지 않고도 이러한 메타 데이터에 액세스 할 수 있습니다.

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

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


아래는 로컬 파일 체크섬을 s3 etag와 비교하는 작업입니다. 나는 파이썬을 사용했다

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


이것은 나를 위해 작동합니다. PHP에서 다음을 사용하여 로컬 파일과 Amazon 파일 간의 체크섬을 비교할 수 있습니다.



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


다음은 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
}

다음은 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);
    }
}

주석 처리 된 코드는 대부분의 사람들이 16 진수로 잘못 변경하는 경우입니다.

참고 URL : https://stackoverflow.com/questions/1775816/how-to-get-the-md5sum-of-a-file-on-amazons-s3

반응형