Skip to content

Commit f78bd13

Browse files
committed
using crt combine checksum function for validating checksums on download
1 parent c76f543 commit f78bd13

File tree

2 files changed

+64
-34
lines changed

2 files changed

+64
-34
lines changed

src/aws-cpp-sdk-transfer/include/aws/transfer/TransferHandle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ namespace Aws
398398
auto it = m_partChecksums.find(partId);
399399
return it != m_partChecksums.end() ? it->second : nullptr;
400400
}
401+
const Aws::Map<int, std::shared_ptr<Aws::Utils::Crypto::Hash>>& GetPartChecksums() const { return m_partChecksums; }
401402

402403
private:
403404
void CleanupDownloadStream();

src/aws-cpp-sdk-transfer/source/transfer/TransferManager.cpp

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <aws/core/utils/memory/stl/AWSStreamFwd.h>
1616
#include <aws/core/utils/memory/stl/AWSStringStream.h>
1717
#include <aws/core/utils/stream/PreallocatedStreamBuf.h>
18+
#include <aws/crt/checksum/CRC.h>
1819
#include <aws/s3/S3Client.h>
1920
#include <aws/s3/model/AbortMultipartUploadRequest.h>
2021
#include <aws/s3/model/CompleteMultipartUploadRequest.h>
@@ -1280,45 +1281,13 @@ namespace Aws
12801281
Aws::IOStream* bufferStream = partState->GetDownloadPartStream();
12811282
assert(bufferStream);
12821283

1283-
// Calculate and validate checksum for this part if validation is enabled
1284+
// checksum for this part if validation is enabled
12841285
if (m_transferConfig.validateChecksums)
12851286
{
12861287
auto hash = handle->GetPartChecksum(partState->GetPartId());
12871288
if (hash && partState->GetDownloadBuffer())
12881289
{
12891290
hash->Update(partState->GetDownloadBuffer(), static_cast<size_t>(partState->GetSizeInBytes()));
1290-
1291-
// Get expected checksum from response
1292-
Aws::String expectedChecksum = GetChecksumFromResult(outcome.GetResult(), m_transferConfig.checksumAlgorithm);
1293-
1294-
// Validate part checksum
1295-
if (!expectedChecksum.empty())
1296-
{
1297-
auto calculatedResult = hash->GetHash();
1298-
if (calculatedResult.IsSuccess())
1299-
{
1300-
Aws::String calculatedChecksum = Utils::HashingUtils::Base64Encode(calculatedResult.GetResult());
1301-
if (calculatedChecksum != expectedChecksum)
1302-
{
1303-
AWS_LOGSTREAM_ERROR(CLASS_TAG, "Transfer handle [" << handle->GetId()
1304-
<< "] Checksum mismatch for part " << partState->GetPartId()
1305-
<< ". Expected: " << expectedChecksum << ", Calculated: " << calculatedChecksum);
1306-
Aws::Client::AWSError<Aws::S3::S3Errors> error(Aws::S3::S3Errors::INTERNAL_FAILURE,
1307-
"ChecksumMismatch",
1308-
"Part checksum validation failed",
1309-
false);
1310-
handle->ChangePartToFailed(partState);
1311-
handle->SetError(error);
1312-
TriggerErrorCallback(handle, error);
1313-
if(partState->GetDownloadBuffer())
1314-
{
1315-
m_bufferManager.Release(partState->GetDownloadBuffer());
1316-
partState->SetDownloadBuffer(nullptr);
1317-
}
1318-
return;
1319-
}
1320-
}
1321-
}
13221291
}
13231292
}
13241293

@@ -1359,7 +1328,67 @@ namespace Aws
13591328
{
13601329
if (failedParts.size() == 0 && handle->GetBytesTransferred() == handle->GetBytesTotalSize())
13611330
{
1362-
// TODO: Combine part checksums and validate full-object checksum when CRT provides combining utility
1331+
// Combine part checksums and validate full-object checksum
1332+
if (m_transferConfig.validateChecksums)
1333+
{
1334+
Aws::String expectedChecksum = GetChecksumFromResult(outcome.GetResult(), m_transferConfig.checksumAlgorithm);
1335+
if (!expectedChecksum.empty())
1336+
{
1337+
auto combinedChecksum = 0ULL;
1338+
bool isCRC64 = (m_transferConfig.checksumAlgorithm == S3::Model::ChecksumAlgorithm::CRC64NVME);
1339+
1340+
for (auto& partChecksum : handle->GetPartChecksums())
1341+
{
1342+
int partNumber = partChecksum.first;
1343+
auto hash = partChecksum.second;
1344+
1345+
// Get part size from completed parts
1346+
auto partSize = handle->GetCompletedParts()[partNumber]->GetSizeInBytes();
1347+
1348+
auto partResult = hash->GetHash();
1349+
auto partData = partResult.GetResult();
1350+
1351+
auto partCrc = isCRC64 ?
1352+
*reinterpret_cast<const unsigned long long*>(partData.GetUnderlyingData()) :
1353+
*reinterpret_cast<const unsigned int*>(partData.GetUnderlyingData());
1354+
1355+
if (combinedChecksum == 0) {
1356+
combinedChecksum = partCrc;
1357+
} else {
1358+
if (m_transferConfig.checksumAlgorithm == S3::Model::ChecksumAlgorithm::CRC32) {
1359+
combinedChecksum = Aws::Crt::Checksum::CombineCRC32(combinedChecksum, partCrc, partSize);
1360+
} else if (m_transferConfig.checksumAlgorithm == S3::Model::ChecksumAlgorithm::CRC32C) {
1361+
combinedChecksum = Aws::Crt::Checksum::CombineCRC32C(combinedChecksum, partCrc, partSize);
1362+
} else if (isCRC64) {
1363+
combinedChecksum = Aws::Crt::Checksum::CombineCRC64NVME(combinedChecksum, partCrc, partSize);
1364+
}
1365+
}
1366+
}
1367+
1368+
// Compare with expected checksum
1369+
Aws::Utils::ByteBuffer checksumBuffer(isCRC64 ? 8 : 4);
1370+
if (isCRC64) {
1371+
*reinterpret_cast<unsigned long long*>(checksumBuffer.GetUnderlyingData()) = combinedChecksum;
1372+
} else {
1373+
*reinterpret_cast<unsigned int*>(checksumBuffer.GetUnderlyingData()) = static_cast<unsigned int>(combinedChecksum);
1374+
}
1375+
Aws::String calculatedChecksum = Utils::HashingUtils::Base64Encode(checksumBuffer);
1376+
1377+
if (calculatedChecksum != expectedChecksum) {
1378+
AWS_LOGSTREAM_ERROR(CLASS_TAG, "Transfer handle [" << handle->GetId()
1379+
<< "] Full-object checksum mismatch. Expected: " << expectedChecksum
1380+
<< ", Calculated: " << calculatedChecksum);
1381+
Aws::Client::AWSError<Aws::S3::S3Errors> error(Aws::S3::S3Errors::INTERNAL_FAILURE,
1382+
"ChecksumMismatch",
1383+
"Full-object checksum validation failed",
1384+
false);
1385+
handle->SetError(error);
1386+
handle->UpdateStatus(TransferStatus::FAILED);
1387+
TriggerErrorCallback(handle, error);
1388+
return;
1389+
}
1390+
}
1391+
}
13631392
outcome.GetResult().GetBody().flush();
13641393
handle->UpdateStatus(TransferStatus::COMPLETED);
13651394
}

0 commit comments

Comments
 (0)