Dun*_*ris 24
对于分段上传,ETag似乎不是MD5(根据Gael Fraiteur的评论).在这些情况下,它包含一个减号和数字的后缀.然而,即使它与MD5的长度相同,即使在减号之前的位似乎也不是MD5.可能后缀是上传的部件数量?
小智 22
AWS的文档ETag说:
实体标签是对象的哈希.ETag仅反映对象内容的更改,而不反映其元数据.ETag可能是也可能不是对象数据的MD5摘要.是否取决于对象的创建方式以及如何加密,如下所述:
- 由PUT对象,POST对象或复制操作或通过AWS管理控制台创建并由SSE-S3或纯文本加密的对象具有ETag,这些ETag是其对象数据的MD5摘要.
- 由PUT对象,POST对象或复制操作或通过AWS管理控制台创建并由SSE-C或SSE-KMS加密的对象具有不是其对象数据的MD5摘要的ETag.
- 如果通过"分段上传"或"零件复制"操作创建对象,则无论加密方法如何,ETag都不是MD5摘要.
参考:http://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html
小智 9
下面是我将本地文件校验和与 s3 etag 进行比较的工作。我用过 Python
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 validationRun Code Online (Sandbox Code Playgroud)
这是一个非常古老的问题,但我很难找到下面的信息,这是我能找到的第一个地方之一,所以我想详细说明一下,以防有人需要。
ETag 是一个 MD5。但是对于分段上传的文件,MD5 是根据每个上传部分的 MD5 的串联计算得出的。所以你不需要在服务器中计算 MD5。只需获取 ETag 即可。
正如@EmersonFarrugia 在这个答案中所说:
假设您上传了一个 14MB 的文件,而您的部分大小为 5MB。计算每个部分对应的3个MD5校验和,即前5MB、后5MB、后4MB的校验和。然后取它们连接的校验和。由于 MD5 校验和是二进制数据的十六进制表示,只需确保采用解码二进制连接的 MD5,而不是 ASCII 或 UTF-8 编码连接的 MD5。完成后,添加连字符和零件数以获取 ETag。
所以你唯一需要的其他东西就是 ETag 和上传部分的大小。但是 ETag 有一个 -NumberOfParts 后缀。因此,您可以将尺寸除以后缀并获得零件尺寸。5Mb 是最小部分大小和默认值。部分大小必须是整数,所以你不能得到每个部分大小为 7,25Mb 的东西。所以应该很容易获得零件尺寸信息。
这是一个在 osx 中制作的脚本,评论中有 Linux 版本:https : //gist.github.com/emersonf/7413337
如果以后无法再访问上面的页面,我将把这两个脚本都留在这里:
Linux版本:
#!/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
Run Code Online (Sandbox Code Playgroud)
OSX 版本:
#!/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
Run Code Online (Sandbox Code Playgroud)
截至 2022 年 2 月 25 日,S3 具有新的校验和检索功能GetObjectAttributes:
Amazon S3 的新 \xe2\x80\x93 附加校验和算法 | AWS 新闻博客
\n\n\n校验和检索 \xe2\x80\x93 新
\nGetObjectAttributes函数返回对象和每个部分(如果适用)的校验和。
该函数支持 SHA-1、SHA-256、CRC-32 和 CRC-32C,用于检查传输的完整性。
\n更新:虽然这种GetObjectAttributes方法在许多情况下都有效,但在某些情况下,例如控制台上传,校验和是根据 16 MB 块计算的。请参见检查对象完整性:
\n\n当您使用 AWS 管理控制台执行某些操作时,如果对象大小超过 16 MB,Amazon S3 将使用分段上传。在这种情况下,校验和不是整个对象的直接校验和,而是基于每个单独部分的校验和值的计算。
\n例如,考虑您使用 REST API 作为单部分直接上传上传的大小为 100 MB 的对象。本例中的校验和是整个对象的校验和。如果您稍后使用控制台重命名该对象、复制它、更改存储类或编辑元数据,Amazon S3 将使用分段上传功能来更新该对象。因此,Amazon S3 为对象创建一个新的校验和值,该值是根据各个部分的校验和值计算得出的。
\n
看起来 MD5 实际上并不是新功能的一个选项,所以这可能无法解决您原来的问题,但 MD5 由于多种原因而被弃用,如果使用备用校验和对您有用,这可能就是您的选择正在寻找。
\n对于那些花时间四处搜索以找出为什么 md5 与 S3 中的 ETag 不同的人。
ETag会根据数据的chuck进行计算,并连接所有md5hash,再次进行md5散列,并将chunk的数量保留在末尾。
这是生成哈希的 C# 版本
string etag = HashOf("file.txt",8);
Run Code Online (Sandbox Code Playgroud)
源代码
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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
70314 次 |
| 最近记录: |