C# 在.NET中带有KMS的AWS S3客户端加密在传输的最后一部分上发出协议冲突异常
下面的代码尝试使用多部分传输、客户端信封加密和AmazonKMS服务将17MB的测试文件复制到S3存储桶,以处理数据加密密钥。多部分块大小为5MB 在传输最后一个(部分)块时,如果C# 在.NET中带有KMS的AWS S3客户端加密在传输的最后一部分上发出协议冲突异常,c#,.net,amazon-web-services,C#,.net,Amazon Web Services,下面的代码尝试使用多部分传输、客户端信封加密和AmazonKMS服务将17MB的测试文件复制到S3存储桶,以处理数据加密密钥。多部分块大小为5MB 在传输最后一个(部分)块时,如果IsLastPart标志设置为true,则对UploadPart的调用将生成一个System.Net.ProtocolViolationException异常,指示要写入流的字节超过指定的内容长度字节大小。 这表明内容长度html标头未更新,以反映加密引擎添加到最后一个密码块以进行正确对齐所需的“pad字节”。因此,当
IsLastPart
标志设置为true
,则对UploadPart
的调用将生成一个System.Net.ProtocolViolationException
异常,指示要写入流的字节超过指定的内容长度字节大小。
这表明内容长度html标头未更新,以反映加密引擎添加到最后一个密码块以进行正确对齐所需的“pad字节”。因此,当添加这些最后的字节时,它们超过了给定的内容长度并生成了此错误
如果IsLastPart
未设置(即左false
),则操作成功,但下载和解密后操作也失败
注意:KmsAlgorithm
类不是由AWS.NET SDK提供的。这个类来自另一个堆栈溢出,因为.NET版本的AWS SDK没有像Java SDK那样提供KMS和S3之间的连接来支持信封加密
那么,使用客户端加密和KMS托管密钥将多部分上传发送到S3的正确方法是什么
static string bucketName = "*****************************";
static string keyName = "test.encrypted.bin";
static string uploadSourcePath = "c:\\temp\\test.bin";
static long partSize = 5 * 1024 * 1024;
static String uploadId = "";
static void Main(string[] args)
{
if (checkRequiredFields())
{
String cmkId = "************************************";
// Prepare our KMS client and kmsAlgorithm
using (AmazonKeyManagementServiceClient kmsClient = new AmazonKeyManagementServiceClient())
using (KMSAlgorithm kmsAlgo = new KMSAlgorithm(kmsClient, cmkId))
{
// Generate the encryption materials object with the algorithm object
EncryptionMaterials encryptionMaterials = new EncryptionMaterials(kmsAlgo);
// Now prepare an S3 crypto client
using (AmazonS3EncryptionClient cryptoClient = new AmazonS3EncryptionClient(encryptionMaterials))
{
// Initiate the multipart upload request specifying the bucket and key values
InitiateMultipartUploadResponse initResp = cryptoClient.InitiateMultipartUpload(
new InitiateMultipartUploadRequest()
{
BucketName = bucketName,
Key = keyName
});
uploadId = initResp.UploadId;
long fileLength = new FileInfo(uploadSourcePath).Length;
long contentLength = fileLength;
long bytesRemaining = fileLength;
List<PartETag> partETags = new List<PartETag>();
int partNumber = 0;
while (bytesRemaining > 0)
{
long transferSize = bytesRemaining > partSize ? partSize : bytesRemaining;
long partIndex = fileLength - bytesRemaining;
partNumber++;
UploadPartResponse resp =
cryptoClient.UploadPart(
new UploadPartRequest()
{
BucketName = bucketName,
Key = keyName,
FilePath = uploadSourcePath,
FilePosition = partIndex,
PartSize = transferSize,
PartNumber = partNumber,
UploadId = uploadId,
IsLastPart = transferSize < AwsS3FileSystemSample1.Program.partSize
});
partETags.Add( new PartETag( partNumber, resp.ETag ));
bytesRemaining -= transferSize;
}
// Now complete the transfer
CompleteMultipartUploadResponse compResp = cryptoClient.CompleteMultipartUpload(
new CompleteMultipartUploadRequest()
{
Key = keyName,
BucketName = bucketName,
UploadId = initResp.UploadId,
PartETags = partETags
});
}
}
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
静态字符串bucketName=“*************************************”;
静态字符串keyName=“test.encrypted.bin”;
静态字符串uploadSourcePath=“c:\\temp\\test.bin”;
静态长零件尺寸=5*1024*1024;
静态字符串uploadId=“”;
静态void Main(字符串[]参数)
{
if(checkRequiredFields())
{
字符串cmkId=“*************************************”;
//准备我们的KMS客户和kmsAlgorithm
使用(AmazonKeyManagementServiceClient kmsClient=new AmazonKeyManagementServiceClient())
使用(KMSAlgorithm kmsAlgo=新的KMSAlgorithm(kmsClient,cmkId))
{
//使用算法对象生成加密材质对象
EncryptionMaterials EncryptionMaterials=新的EncryptionMaterials(kmsAlgo);
//现在准备一个S3加密客户端
使用(AmazonS3EncryptionClient cryptoClient=新的AmazonS3EncryptionClient(encryptionMaterials))
{
//启动指定bucket和key值的多部分上传请求
InitiateMultipartUploadResponse initResp=cryptoClient.InitiateMultipartUpload(
新的InitiateMultipartUploadRequest()
{
BucketName=BucketName,
Key=keyName
});
uploadId=initResp.uploadId;
long fileLength=newfileinfo(uploadSourcePath).Length;
long contentLength=文件长度;
long bytes剩余=文件长度;
List partETags=新列表();
int partNumber=0;
while(字节剩余>0)
{
长传输大小=字节剩余>零件大小?零件大小:字节剩余;
long partIndex=文件长度-剩余字节数;
partNumber++;
上传部分响应响应=
cryptoClient.UploadPart(
新建UploadPartRequest()
{
BucketName=BucketName,
Key=keyName,
FilePath=uploadSourcePath,
FilePosition=partIndex,
零件尺寸=转移尺寸,
零件号=零件号,
UploadId=UploadId,
IsLastPart=transferSize
对于任何错误和帮助,我们深表歉意。感谢您尝试在链接帖子中使用我的实现 虽然我没有读过任何明确支持这一点的文章,但我认为AmazonS3加密客户端可能与多部分上传不兼容。虽然它不是确定的,但我还没有找到一个在多部分上传上同时使用AmazonS3加密客户端的Java示例(SDK有一个KMS实现)。我怀疑的原因是,文件是使用链式块加密的,如果多部分上传的每个部分都是逐段加密的,链式块将被破坏,每个部分的单独初始化向量将丢失以进行解密
我想知道的唯一方法就是首先用Java测试它。在经过大量测试和在git hub上进行了少量代码探索之后
while (bytesRemaining > 0)
{
long transferSize = bytesRemaining > partSize ? partSize : bytesRemaining;
long partIndex = fileLength - bytesRemaining;
bytesRemaining -= transferSize;
bool isLastPart = bytesRemaining == 0;
partNumber++;
UploadPartResponse resp =
cryptoClient.UploadPart(
new UploadPartRequest()
{
BucketName = bucketName,
Key = keyName,
FilePath = uploadSourcePath,
FilePosition = partIndex,
PartSize = isLastPart ? 0 : transferSize,
PartNumber = partNumber,
UploadId = uploadId,
IsLastPart = isLastPart
});
partETags.Add( new PartETag( partNumber, resp.ETag ));
}