

# 고객 제공 키(SSE-C)로 서버 측 암호화 사용
<a name="ServerSideEncryptionCustomerKeys"></a>

서버 측 암호화는 저장된 데이터를 보호하기 위한 것입니다. 서버 측 암호화는 객체 메타데이터가 아닌 객체 데이터만 암호화합니다. 범용 버킷에서 고객 제공 키를 사용한 서버 측 암호화(SSE-C)를 사용하여 자체 암호화 키로 데이터를 암호화할 수 있습니다. 요청의 일부로 제공한 암호화 키를 사용하여 Amazon S3는 디스크에 쓸 때 데이터 암호화를 관리하고 객체에 액세스할 때 데이터 암호 해독을 관리합니다. 따라서 데이터 암호화 및 암호 해독을 수행하기 위해 어떠한 코드도 사용할 필요가 없으며, 사용자는 자신이 제공한 암호화 키를 관리하기만 하면 됩니다.

Amazon S3의 최신 사용 사례에서는 더 이상 SSE-C를 사용하지 않습니다. SSE-C는 Amazon S3 관리형 키(SSE-S3) 또는 AWS KMS 키를 사용한 서버 측 암호화(SSE-KMS)에 비해 유연성이 부족하기 때문입니다. SSE-C는 SSE-C 암호화 데이터와 상호 작용할 때마다 암호화 키를 제공해야 하므로 SSE-C 키를 S3 버킷에서 데이터를 읽는 다른 사용자, 역할 또는 AWS 서비스와 공유하여 데이터를 운영할 수 없습니다. AWS에서 SSE-KMS에 대한 광범위한 지원으로 인해 대부분의 최신 워크로드는 SSE-KMS의 유연성이 부족하기 때문에 SSE-C 암호화를 사용하지 않습니다. SSE-KMS에 대한 자세한 내용은 [AWS KMS 키를 사용한 서버 측 암호화(SSE-KMS) 사용](UsingKMSEncryption.md) 섹션을 참조하세요.

버킷에 기록되는 객체에 SSE-C 암호화가 사용되지 않도록 하려면 버킷의 기본 암호화 구성을 변경할 때 SSE-C 암호화를 차단합니다. 범용 버킷에 대해 SSE-C가 차단되면 SSE-C 암호화를 지정하는 모든 `PutObject`, `CopyObject`, `PostObject`, 멀티파트 업로드 또는 복제 요청이 `HTTP 403 AccessDenied` 오류와 함께 거부됩니다. SSE-C 차단에 대한 자세한 내용은 [범용 버킷에 대한 SSE-C 차단 또는 차단 해제](blocking-unblocking-s3-c-encryption-gpb.md) 섹션을 참조하세요.

SSE-C 사용에 따르는 추가 비용은 없습니다. 그러나 SSE-C 구성 및 사용 요청에는 표준 Amazon S3 요청 요금이 발생합니다. 요금에 대한 자세한 내용은 [Amazon S3 요금](https://aws.amazon.com/s3/pricing/)을 참조하십시오.

**중요**  
2026년 4월부터 AWS는 모든 새 버킷에 대해 고객 제공 키를 사용한 서버 측 암호화(SSE-C)를 비활성화합니다. 또한 SSE-C 암호화 데이터가 없는 AWS 계정의 모든 기존 버킷에 대해 SSE-C 암호화가 비활성화됩니다. 이러한 변경으로 인해 SSE-C 암호화가 필요한 몇 가지 애플리케이션은 버킷을 생성한 후 [https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html) API를 통해 SSE-C 사용을 의도적으로 활성화해야 합니다. 이러한 경우 자동화 스크립트,CloudFormation 템플릿 또는 기타 인프라 구성 도구를 업데이트하여 해당 설정을 구성해야 할 수 있습니다. 자세한 내용은 [AWS 스토리지 블로그 게시물](https://aws.amazon.com/blogs/storage/advanced-notice-amazon-s3-to-disable-the-use-of-sse-c-encryption-by-default-for-all-new-buckets-and-select-existing-buckets-in-april-2026/)을 참조하세요.

## SSE-C 사용 전 고려 사항
<a name="considerations-before-using-sse-c"></a>
+ SSE-C를 사용할 때 S3는 암호화 키를 저장하지 않습니다. 누구나 S3에서 SSE-C 암호화 데이터를 다운로드하도록 하려면 암호화 키를 제공해야 합니다.
  + 암호화 키가 사용되는 매핑을 관리하여 객체를 암호화합니다. 객체에 대해 제공한 암호화 키는 직접 추적해야 합니다. 즉, 암호화 키를 분실하면 객체도 분실합니다.
  + 암호화 키는 클라이언트 측에서 관리하기 때문에 클라이언트 측에서 키 교체와 같은 추가적인 보안 조치를 관리합니다.
  + 이 설계로 인해 데이터에서 작업할 다른 사용자, 역할 또는 AWS 서비스와 SSE-C 키를 공유하기 어려울 수 있습니다. AWS에서 SSE-KMS에 대한 광범위한 지원으로 인해 대부분의 최신 워크로드는 SSE-KMS의 유연성이 부족하기 때문에 SSE-C를 사용하지 않습니다. SSE-KMS에 대한 자세한 내용은 [AWS KMS 키를 사용한 서버 측 암호화(SSE-KMS) 사용](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html)을 참조하세요.
  + 즉, SSE-C로 암호화된 객체는 AWS 관리형 서비스에서 기본적으로 해독할 수 없습니다.
+ 요청에 SSE-C 헤더를 지정할 때는 HTTPS를 사용해야 합니다.
  + Amazon S3는 SSE-C를 사용할 때 HTTP를 통해 전송된 모든 요청을 거부합니다. 보안상의 이유로 인해, 보안에 취약할 수 있는 HTTP를 통해 키를 보내면 오류가 발생할 수 있음을 유의하십시오. 키를 취소하고 적절하게 교체합니다.
+ 버전 관리가 활성화된 버킷의 경우 업로드하는 각 객체 버전에는 자체 암호화 키가 있습니다. 어떤 객체 버전에 어떤 암호화 키가 사용되었는지는 직접 추적해야 합니다.
+ SSE-C는 Amazon S3 콘솔에서 지원되지 않습니다. Amazon S3 콘솔을 사용하여 객체를 업로드하거나 SSE-C 암호화를 지정할 수 없습니다. 또한 SSE-C를 사용하여 저장된 기존 객체를 업데이트할 수 도 없습니다(예: 스토리지 클래스 변경 또는 메타데이터 추가).

**Topics**
+ [SSE-C 사용 전 고려 사항](#considerations-before-using-sse-c)
+ [고객 제공 키를 사용한 서버 측 암호화 지정(SSE-C).](specifying-s3-c-encryption.md)
+ [범용 버킷에 대한 SSE-C 차단 또는 차단 해제](blocking-unblocking-s3-c-encryption-gpb.md)
+ [새 버킷의 기본 SSE-C 설정 FAQ](default-s3-c-encryption-setting-faq.md)

# 고객 제공 키를 사용한 서버 측 암호화 지정(SSE-C).
<a name="specifying-s3-c-encryption"></a>

고객 제공 키를 사용한 서버 측 암호화(SSE-C)를 사용하려면 먼저 Amazon S3 범용 버킷의 기본 암호화 구성에서 SSE-C가 차단된 암호화 유형이 아닌지 확인합니다. 차단된 경우 버킷의 기본 암호화 구성을 업데이트하여 이 암호화 유형을 활성화할 수 있습니다. 그런 다음 필수 헤더를 전달하여 업로드 요청에 SSE-C를 사용할 수 있습니다. [SSE-C로 데이터 쓰기를 지원하는 Amazon S3 작업](#amazon-s3-actions-that-support-writing-data-with-sse-c)를 참조하고 [SSE-C 객체 암호화 및 복호화 요청에 필요한 S3 API 헤더](#s3-api-headers-required-for-sse-c-object-encryption-and-decryption-requests)를 포함해야 합니다.

SSE-C를 지정하는 객체를 업로드하면 Amazon S3는 제공된 암호화 키를 사용하여 AES-256 암호화를 데이터에 적용합니다. 그런 다음 Amazon S3는 메모리에서 암호화 키를 제거합니다. 객체를 검색할 경우 요청에 포함된 것과 동일한 암호화 키를 제공해야 합니다. Amazon S3는 제공된 암호화 키가 일치하는지 확인한 후 객체 데이터를 반환하기 전에 객체의 암호화를 해독합니다.

SSE-C를 사용하기 전에 [SSE-C 사용 전 고려 사항](ServerSideEncryptionCustomerKeys.md#considerations-before-using-sse-c)을 검토했는지 확인합니다.

**참고**  
Amazon S3는 제공된 암호화 키를 저장하지 않습니다. 대신에 임의로 암호화 키의 솔트 해시 기반 메시지 인증 코드(HMAC) 값을 저장하여 향후 요청을 검증합니다. 솔트 HMAC 값은 암호화 키의 값을 파생하거나 암호화된 객체의 콘텐츠를 해독하기 위해 사용할 수 없습니다. 즉, 암호화 키가 없어지면 객체도 없어집니다.

**Topics**
+ [SSE-C 작업 및 필수 헤더](#sse-c-actions-and-required-headers)
+ [SSE-C 암호화를 적용하는 버킷 정책 예제](#example-bucket-policy-to-enforce-sse-c-encryption)
+ [미리 서명된 URL 및 SSE-C](#ssec-and-presignedurl)
+ [SSE-C를 사용하여 요청 생성](#making-requests-with-sse-c)
+ [REST API 사용](#using-rest-api-sse-c)
+ [AWS SDK를 사용하여 PUT, GET, Head 및 Copy 작업에 SSE-C 지정](#sse-c-using-sdks)
+ [AWS SDK를 사용하여 멀티파트 업로드를 위한 SSE-C 지정](#sse-c-using-sdks-multipart-uploads)

## SSE-C 작업 및 필수 헤더
<a name="sse-c-actions-and-required-headers"></a>

지원되는 S3 API에서 SSE-C를 지정하려면 특정 요청 파라미터를 전달해야 합니다.

**참고**  
Amazon S3의 `PutBucketEncryption` API는 버킷에 대한 기본 서버 측 암호화를 구성하는 데 사용됩니다. 그러나 `PutBucketEncryption`은 SSE-C를 활성화하는 기능을 버킷의 기본 암호화 방법으로 지원하지 않습니다. SSE-C는 각 객체 업로드 또는 다운로드 요청과 함께 Amazon S3에 암호화 키를 제공하는 객체 수준 암호화 방법입니다. Amazon S3는이 키를 사용하여 요청 중에 객체를 암호화 또는 복호화한 다음 키를 폐기합니다. 즉, SSE-C는 기본 버킷 설정이 아닌 객체별로 활성화됩니다.

### SSE-C로 데이터 쓰기를 지원하는 Amazon S3 작업
<a name="amazon-s3-actions-that-support-writing-data-with-sse-c"></a>

다음 API 작업 또는 작업을 사용하여 범용 버킷에 객체를 쓸 때 고객 제공 키를 사용한 서버 측 암호화(SSE-C)를 요청할 수 있습니다.
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html)
+ [https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html)

**참고**  
S3 복제는 SSE-C로 암호화된 객체를 지원합니다. 암호화된 객체 복제에 대한 자세한 내용은 [암호화(SSE-S3, SSE-KMS, DSSE-KMS, SSE-C)된 객체 복제](replication-config-for-kms-objects.md) 섹션을 참조하십시오.

### SSE-C 객체 암호화 및 복호화 요청에 필요한 S3 API 헤더
<a name="s3-api-headers-required-for-sse-c-object-encryption-and-decryption-requests"></a>

SSE-C로 객체를 암호화하거나 복호화하려면 다음 세 가지 API 헤더를 제공해야 합니다.
+ `x-amz-server-side-encryption-customer-algorithm` 이 헤더를 사용하여 암호화 알고리즘을 지정합니다. 헤더 값은 AES256이어야 합니다.
+ `x-amz-server-side-encryption-customer-key` 이 헤더를 사용하여 256비트의 base64 인코딩 암호화 키를 Amazon S3에 제공하여 데이터를 암호화하거나 복호화합니다.
+ `x-amz-server-side-encryption-customer-key-MD5` 이 헤더를 사용하여 RFC 1321에 따라 암호화 키의 128비트 base64 인코딩 MD5 다이제스트를 제공합니다. Amazon S3는 메시지 무결성 검사에 이 헤더를 사용하여 암호화 키가 오류 없이 전송되었음을 확인합니다.

### SSE-C로 암호화된 소스 객체를 복사하기 위한 요청에 필요한 S3 API 헤더
<a name="s3-api-headers-required-for-requests-to-copy-source-objects-encrypted-with-sse-c"></a>

SSE-C로 암호화된 소스 객체를 복사하려면 다음 세 가지 API 헤더를 제공해야 합니다.
+ `x-amz-copy-source-server-side-encryption-customer-algorithm` 이 헤더를 포함하여 Amazon S3가 원본 객체 복호화에 사용해야 하는 알고리즘을 지정합니다. 이 값은 AES256이어야 합니다.
+ `x-amz-copy-source-server-side-encryption-customer-key` 이 헤더를 포함하여 Amazon S3가 원본 객체의 암호화를 복호화하는 데 사용할 base64 인코딩 암호화 키를 제공합니다. 이 암호화 키는 원본 객체를 만들 때 Amazon S3에 제공한 것이어야 하며, 그렇지 않으면 Amazon S3가 객체의 암호를 해독할 수 없습니다.
+ `x-amz-copy-source-server-side-encryption-customer-key-MD5` 이 헤더를 포함하여 RFC 1321에 따라 암호화 키의 128비트 base64 인코딩 MD5 다이제스트를 제공합니다.

## SSE-C 암호화를 적용하는 버킷 정책 예제
<a name="example-bucket-policy-to-enforce-sse-c-encryption"></a>

Amazon S3 버킷에 작성된 모든 객체에 대해 SSE-C를 요구하려면 버킷 정책을 사용하면 됩니다. 예를 들어 다음 버킷 정책은 SSE-C를 요청하는 `x-amz-server-side-encryption-customer-algorithm` 헤더가 포함되지 않은 모든 요청에 대해 객체 업로드(`s3:PutObject`) 권한을 거부합니다.

```
{  
"Version":"2012-10-17",		 	 	                      
    "Id": "PutObjectPolicy",  
    "Statement": [  
        {  
"Sid": "RequireSSECObjectUploads",  
            "Effect": "Deny",  
            "Principal": "*",  
            "Action": "s3:PutObject",  
            "Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*",  
            "Condition": {  
            "Null": {  
              "s3:x-amz-server-side-encryption-customer-algorithm": "true"  
                }  
            }  
        }  
    ]  
}
```

**중요**  
버킷 정책을 사용하여 `s3:PutObject`에서 SSE-C를 요구하는 경우, 모든 멀티파트 업로드 요청(CreateMultipartUpload, UploadPart, CompleteMultipartUpload)에 `x-amz-server-side-encryption-customer-algorithm` 헤더를 포함시켜야 합니다.

## 미리 서명된 URL 및 SSE-C
<a name="ssec-and-presignedurl"></a>

새로운 객체 업로드, 기존 객체 또는 객체 메타데이터 검색과 같은 작업에 사용되는 미리 서명된 URL을 생성할 수 있습니다. 미리 서명된 URL은 다음과 같이 SSE-C를 지원합니다.
+ 미리 서명된 URL을 만들 때 서명 계산에 `x-amz-server-side-encryption-customer-algorithm` 헤더를 사용하여 알고리즘을 지정해야 합니다.
+ 새로운 객체 업로드, 기존 객체 또는 객체 메타데이터 전용 검색에 미리 서명된 URL을 사용하는 경우, 클라이언트 애플리케이션의 요청에서 모든 암호화 헤더를 제공해야 합니다.
**참고**  
비 SSE-C 객체의 경우, 데이터에 액세스하기 위해 미리 서명된 URL을 생성하여 브라우저에 직접 붙여 넣을 수 있습니다.  
하지만 SSE-C 객체에는 이렇게 할 수 없습니다. 미리 서명된 URL 이외에 SSE-C 객체에 고유한 HTTP 헤더도 포함해야 하기 때문입니다. 따라서 프로그래밍 방식으로만 SSE-C 객체에 미리 서명된 URL을 생성할 수 있습니다.

미리 서명된 URL에 대한 자세한 내용은 섹선을 참조하세요[미리 서명된 URL을 통해 객체 다운로드 및 업로드](using-presigned-url.md)

## SSE-C를 사용하여 요청 생성
<a name="making-requests-with-sse-c"></a>

 REST API를 사용하여 객체를 생성할 때 고객 제공 키(SSE-C)를 사용하여 서버 측 암호화를 지정할 수 있습니다. SSE-C를 사용하는 경우 [SSE-C로 암호화된 소스 객체를 복사하기 위한 요청에 필요한 S3 API 헤더](#s3-api-headers-required-for-requests-to-copy-source-objects-encrypted-with-sse-c)를 사용하여 암호화 키 정보를 제공해야 합니다. AWS SDK 래퍼 라이브러리를 사용하여 이러한 헤더를 요청에 추가할 수 있습니다. 필요한 경우 애플리케이션에서 직접 Amazon S3 REST API를 호출할 수 있습니다.

**중요**  
고객 제공 키를 사용한 서버 측 암호화(SSE-C)를 지정하기 전에, 범용 버킷에 대해 SSE-C 암호화가 차단되지 않았는지 확인합니다. 자세한 내용은 [범용 버킷에 대한 SSE-C 차단 또는 차단 해제](blocking-unblocking-s3-c-encryption-gpb.md) 섹션을 참조하세요.

**참고**  
Amazon S3 콘솔을 사용하여 객체를 업로드하고 SSE-C를 요청할 수 없습니다. 또한, SSE-C를 사용하여 저장된 기존 객체를 업데이트할 수도 없습니다(예: 스토리지 클래스 변경 또는 메타데이터 추가). [SSE-C 객체 암호화 및 복호화 요청에 필요한 S3 API 헤더](#s3-api-headers-required-for-sse-c-object-encryption-and-decryption-requests) 섹션을 참조하세요.

## REST API 사용
<a name="using-rest-api-sse-c"></a>

### SSE-C를 지원하는 Amazon S3 REST API
<a name="sse-c-supported-apis"></a>

다음 Amazon S3 API는 고객 제공 암호화 키(SSE-C)로 서버 측 암호화를 지원합니다.
+ **GET 작업** - GET API([GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html) 참조)를 사용하여 객체를 검색할 때 요청 헤더를 지정할 수 있습니다.
+ **HEAD 작업** - HEAD API([HeadObject](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectHEAD.html) 참조)를 사용하여 객체 메타데이터를 검색하려면 이러한 요청 헤더를 지정하면 됩니다.
+ **PUT 작업** - PUT Object API([PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html) 참조)를 사용하여 데이터를 업로드할 때 이러한 요청 헤더를 지정할 수 있습니다.
+ **멀티파트 업로드 ** - 멀티파트 업로드 API를 사용하여 대형 객체를 업로드할 때 이 헤더를 지정할 수 있습니다. 시작 요청에서 이 헤더를 지정하고([멀티파트 업로드 시작에 관한 문서](https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadInitiate.html) 참조) 각각의 후속 부분은 요청을 업로드합니다([Upload Part](https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadUploadPart.html) 또는 [UploadPartCopy](https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadUploadPartCopy.html) 참조). 각 파트 업로드 요청에서 암호화 정보는 시작 멀티파트 업로드 요청의 시작에서 제공한 내용과 동일해야 합니다.
+ **POST 작업** - POST 작업([객체 POST에 관한 문서](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) 참조)을 사용하여 객체를 업로드할 경우에는 요청 헤더 대신 양식 필드에 동일한 정보를 제공합니다.
+ **복사 작업** - 객체를 복사([CopyObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html) 참조)하려면 원본 객체 및 대상 객체가 있어야 합니다.
  + 대상 객체의 암호화 유형을 지정하려면 `x-amz-server-side-encryption ` 요청 헤더를 제공해야 합니다.
  + SSE-C를 사용하여 대상 객체를 암호화하려는 경우, S3 API [SSE-C 객체 암호화 및 복호화 요청에 필요한 S3 API 헤더](#s3-api-headers-required-for-sse-c-object-encryption-and-decryption-requests)를 사용하여 암호화 정보를 제공해야 합니다.
  + SSE-C를 사용하여 소스 객체를 암호화했다면 S3 API 헤더 [SSE-C로 암호화된 소스 객체를 복사하기 위한 요청에 필요한 S3 API 헤더](#s3-api-headers-required-for-requests-to-copy-source-objects-encrypted-with-sse-c)를 사용하여 암호화 키 정보를 제공해야 합니다.

## AWS SDK를 사용하여 PUT, GET, Head 및 Copy 작업에 SSE-C 지정
<a name="sse-c-using-sdks"></a>

다음 예제에서는 객체에 대해 고객 제공 키를 사용한 서버 측 암호화(SSE-C)를 요청하는 방법을 보여줍니다. 이 예제에서는 다음 작업을 수행합니다. 각 작업에서는 요청에 SSE-C 관련 헤더를 지정하는 방법을 보여 줍니다.
+ **객체 넣기** - 객체를 업로드하고 고객 제공 암호화 키를 사용하여 서버 측 암호화를 요청합니다.
+ **객체 가져오기** - 앞 단계에서 업로드한 객체를 다운로드합니다. 요청 시 객체가 업로드되었을 때 제공한 것과 동일한 암호화 정보를 제공합니다. Amazon S3는 객체의 암호를 해독하여 사용자에게 반환하기 위해 이 정보가 필요합니다.
+ **객체 메타데이터 가져오기** - 객체의 메타데이터를 검색합니다. 객체 생성 시 사용한 것과 동일한 암호화 정보를 제공합니다.
+ **객체 복사** - 이전에 업로드한 객체의 복사본을 만듭니다. 원본 객체가 SSE-C를 사용하여 저장되기 때문에 복사 요청에 암호화 정보를 제공해야 합니다. 기본적으로 Amazon S3는 사용자가 명시적으로 요청하는 경우에만 객체의 사본을 암호화합니다. 이 예제에서는 Amazon S3에 객체의 암호화된 사본을 저장하도록 지시합니다.

------
#### [ Java ]

**참고**  
이 예제에서는 단일 작업으로 객체를 업로드하는 방법을 보여 줍니다. 멀티파트 업로드 API를 사용하여 대용량 객체를 업로드할 때는 다음 예제에서 보여주는 방식과 동일한 방식으로 암호화 정보를 제공합니다. AWS SDK for Java를 사용하는 멀티파트 업로드에 대한 예제는 [멀티파트 업로드를 사용한 객체 업로드](mpu-upload-object.md) 섹션을 참조하십시오.

필요한 암호화 정보를 추가하려면 요청에 `SSECustomerKey`를 포함합니다. `SSECustomerKey` 클래스에 대한 자세한 내용은 REST API 섹션을 참조하십시오.

실제 예제를 작성 및 테스트하는 방법에 대한 자세한 내용은 AWS SDK for Java 개발자 안내서의 [시작하기](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/getting-started.html) 섹션을 참조하세요.

**Example**  

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;

import javax.crypto.KeyGenerator;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class ServerSideEncryptionUsingClientSideEncryptionKey {
    private static SSECustomerKey SSE_KEY;
    private static AmazonS3 S3_CLIENT;
    private static KeyGenerator KEY_GENERATOR;

    public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
        Regions clientRegion = Regions.DEFAULT_REGION;
        String bucketName = "*** Bucket name ***";
        String keyName = "*** Key name ***";
        String uploadFileName = "*** File path ***";
        String targetKeyName = "*** Target key name ***";

        // Create an encryption key.
        KEY_GENERATOR = KeyGenerator.getInstance("AES");
        KEY_GENERATOR.init(256, new SecureRandom());
        SSE_KEY = new SSECustomerKey(KEY_GENERATOR.generateKey());

        try {
            S3_CLIENT = AmazonS3ClientBuilder.standard()
                    .withCredentials(new ProfileCredentialsProvider())
                    .withRegion(clientRegion)
                    .build();

            // Upload an object.
            uploadObject(bucketName, keyName, new File(uploadFileName));

            // Download the object.
            downloadObject(bucketName, keyName);

            // Verify that the object is properly encrypted by attempting to retrieve it
            // using the encryption key.
            retrieveObjectMetadata(bucketName, keyName);

            // Copy the object into a new object that also uses SSE-C.
            copyObject(bucketName, keyName, targetKeyName);
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }

    private static void uploadObject(String bucketName, String keyName, File file) {
        PutObjectRequest putRequest = new PutObjectRequest(bucketName, keyName, file).withSSECustomerKey(SSE_KEY);
        S3_CLIENT.putObject(putRequest);
        System.out.println("Object uploaded");
    }

    private static void downloadObject(String bucketName, String keyName) throws IOException {
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, keyName).withSSECustomerKey(SSE_KEY);
        S3Object object = S3_CLIENT.getObject(getObjectRequest);

        System.out.println("Object content: ");
        displayTextInputStream(object.getObjectContent());
    }

    private static void retrieveObjectMetadata(String bucketName, String keyName) {
        GetObjectMetadataRequest getMetadataRequest = new GetObjectMetadataRequest(bucketName, keyName)
                .withSSECustomerKey(SSE_KEY);
        ObjectMetadata objectMetadata = S3_CLIENT.getObjectMetadata(getMetadataRequest);
        System.out.println("Metadata retrieved. Object size: " + objectMetadata.getContentLength());
    }

    private static void copyObject(String bucketName, String keyName, String targetKeyName)
            throws NoSuchAlgorithmException {
        // Create a new encryption key for target so that the target is saved using
        // SSE-C.
        SSECustomerKey newSSEKey = new SSECustomerKey(KEY_GENERATOR.generateKey());

        CopyObjectRequest copyRequest = new CopyObjectRequest(bucketName, keyName, bucketName, targetKeyName)
                .withSourceSSECustomerKey(SSE_KEY)
                .withDestinationSSECustomerKey(newSSEKey);

        S3_CLIENT.copyObject(copyRequest);
        System.out.println("Object copied");
    }

    private static void displayTextInputStream(S3ObjectInputStream input) throws IOException {
        // Read one line at a time from the input stream and display each line.
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        System.out.println();
    }
}
```

------
#### [ .NET ]

**참고**  
멀티파트 업로드 API를 사용하여 대형 객체를 업로드하는 예제는 [멀티파트 업로드를 사용한 객체 업로드](mpu-upload-object.md) 및 [AWS SDK 사용(하위 수준 API)](mpu-upload-object.md#mpu-upload-low-level) 섹션을 참조하세요.

코드 예제 설정 및 실행에 대한 자세한 내용은 *AWS SDK for .NET 개발자 안내서*의 [AWS SDK for .NET 시작하기](https://docs.aws.amazon.com/sdk-for-net/latest/developer-guide/net-dg-setup.html)를 참조하세요.

**Example**  

```
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace Amazon.DocSamples.S3
{
    class SSEClientEncryptionKeyObjectOperationsTest
    {
        private const string bucketName = "*** bucket name ***"; 
        private const string keyName = "*** key name for new object created ***"; 
        private const string copyTargetKeyName = "*** key name for object copy ***";
        // Specify your bucket region (an example region is shown).
        private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2;
        private static IAmazonS3 client;

        public static void Main()
        {
            client = new AmazonS3Client(bucketRegion);
            ObjectOpsUsingClientEncryptionKeyAsync().Wait();
        }
        private static async Task ObjectOpsUsingClientEncryptionKeyAsync()
        {
            try
            {
                // Create an encryption key.
                Aes aesEncryption = Aes.Create();
                aesEncryption.KeySize = 256;
                aesEncryption.GenerateKey();
                string base64Key = Convert.ToBase64String(aesEncryption.Key);

                // 1. Upload the object.
                PutObjectRequest putObjectRequest = await UploadObjectAsync(base64Key);
                // 2. Download the object and verify that its contents matches what you uploaded.
                await DownloadObjectAsync(base64Key, putObjectRequest);
                // 3. Get object metadata and verify that the object uses AES-256 encryption.
                await GetObjectMetadataAsync(base64Key);
                // 4. Copy both the source and target objects using server-side encryption with 
                //    a customer-provided encryption key.
                await CopyObjectAsync(aesEncryption, base64Key);
            }
            catch (AmazonS3Exception e)
            {
                Console.WriteLine("Error encountered ***. Message:'{0}' when writing an object", e.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message);
            }
        }

        private static async Task<PutObjectRequest> UploadObjectAsync(string base64Key)
        {
            PutObjectRequest putObjectRequest = new PutObjectRequest
            {
                BucketName = bucketName,
                Key = keyName,
                ContentBody = "sample text",
                ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                ServerSideEncryptionCustomerProvidedKey = base64Key
            };
            PutObjectResponse putObjectResponse = await client.PutObjectAsync(putObjectRequest);
            return putObjectRequest;
        }
        private static async Task DownloadObjectAsync(string base64Key, PutObjectRequest putObjectRequest)
        {
            GetObjectRequest getObjectRequest = new GetObjectRequest
            {
                BucketName = bucketName,
                Key = keyName,
                // Provide encryption information for the object stored in Amazon S3.
                ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                ServerSideEncryptionCustomerProvidedKey = base64Key
            };

            using (GetObjectResponse getResponse = await client.GetObjectAsync(getObjectRequest))
            using (StreamReader reader = new StreamReader(getResponse.ResponseStream))
            {
                string content = reader.ReadToEnd();
                if (String.Compare(putObjectRequest.ContentBody, content) == 0)
                    Console.WriteLine("Object content is same as we uploaded");
                else
                    Console.WriteLine("Error...Object content is not same.");

                if (getResponse.ServerSideEncryptionCustomerMethod == ServerSideEncryptionCustomerMethod.AES256)
                    Console.WriteLine("Object encryption method is AES256, same as we set");
                else
                    Console.WriteLine("Error...Object encryption method is not the same as AES256 we set");

                // Assert.AreEqual(putObjectRequest.ContentBody, content);
                // Assert.AreEqual(ServerSideEncryptionCustomerMethod.AES256, getResponse.ServerSideEncryptionCustomerMethod);
            }
        }
        private static async Task GetObjectMetadataAsync(string base64Key)
        {
            GetObjectMetadataRequest getObjectMetadataRequest = new GetObjectMetadataRequest
            {
                BucketName = bucketName,
                Key = keyName,

                // The object stored in Amazon S3 is encrypted, so provide the necessary encryption information.
                ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                ServerSideEncryptionCustomerProvidedKey = base64Key
            };

            GetObjectMetadataResponse getObjectMetadataResponse = await client.GetObjectMetadataAsync(getObjectMetadataRequest);
            Console.WriteLine("The object metadata show encryption method used is: {0}", getObjectMetadataResponse.ServerSideEncryptionCustomerMethod);
            // Assert.AreEqual(ServerSideEncryptionCustomerMethod.AES256, getObjectMetadataResponse.ServerSideEncryptionCustomerMethod);
        }
        private static async Task CopyObjectAsync(Aes aesEncryption, string base64Key)
        {
            aesEncryption.GenerateKey();
            string copyBase64Key = Convert.ToBase64String(aesEncryption.Key);

            CopyObjectRequest copyRequest = new CopyObjectRequest
            {
                SourceBucket = bucketName,
                SourceKey = keyName,
                DestinationBucket = bucketName,
                DestinationKey = copyTargetKeyName,
                // Information about the source object's encryption.
                CopySourceServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                CopySourceServerSideEncryptionCustomerProvidedKey = base64Key,
                // Information about the target object's encryption.
                ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                ServerSideEncryptionCustomerProvidedKey = copyBase64Key
            };
            await client.CopyObjectAsync(copyRequest);
        }
    }
}
```

------

## AWS SDK를 사용하여 멀티파트 업로드를 위한 SSE-C 지정
<a name="sse-c-using-sdks-multipart-uploads"></a>

앞 섹션의 예제에서는 PUT, GET, Head 및 Copy 작업에서 고객 제공 키(SSE-C)를 사용하는 서버 측 암호화를 요청하는 방법을 알아보았으며, 이 섹션에서는 SSE-C를 지원하는 기타 Amazon S3 API에 대해 소개합니다.

------
#### [ Java ]

멀티파트 업로드 API를 사용하여 대형 객체를 업로드할 수 있습니다. 자세한 내용은 [Amazon S3에서 멀티파트 업로드를 사용한 객체 업로드 및 복사](mpuoverview.md) 섹션을 참조하세요. 상위 수준 또는 하위 수준의 API를 사용하여 대형 객체를 업로드할 수 있습니다. 이들 API는 요청의 암호화 관련 헤더를 지원합니다.
+ 고급 `TransferManager` API를 사용할 때는 `PutObjectRequest`에 암호화 관련 헤더를 제공합니다. 자세한 내용은 [멀티파트 업로드를 사용한 객체 업로드](mpu-upload-object.md) 섹션을 참조하세요.
+ 하위 수준 API를 사용할 경우 `InitiateMultipartUploadRequest`에 암호화 관련 정보를 제공하고 각 `UploadPartRequest`에 동일한 암호화 정보를 제공합니다. `CompleteMultipartUploadRequest`에서는 암호화 관련 헤더를 제공할 필요가 없습니다. 예제는 [AWS SDK 사용(하위 수준 API)](mpu-upload-object.md#mpu-upload-low-level)을 참조하세요.

다음 예제에서는 `TransferManager`를 사용하여 객체를 만들고 SSE-C 관련 정보를 제공하는 방법을 보여 줍니다. 이 예제는 다음을 수행합니다.
+ `TransferManager.upload()` 메서드를 사용하여 객체를 생성합니다. `PutObjectRequest` 인스턴스에서 요청의 암호화 키 정보를 제공합니다. Amazon S3에서는 고객이 제공하는 키를 사용하여 객체를 암호화합니다.
+ `TransferManager.copy()` 메서드를 호출하여 객체의 복사본을 생성합니다. 이 예제에서는 Amazon S3에 새 `SSECustomerKey`를 사용하여 객체 복사본을 암호화하도록 지시합니다. 원본 객체가 SSE-C를 사용하여 암호화되기 때문에 Amazon S3가 복사 전에 객체의 암호를 해독할 수 있도록 `CopyObjectRequest` 실행 시 원본 객체의 암호화 키도 제공됩니다.

**Example**  

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.CopyObjectRequest;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.SSECustomerKey;
import com.amazonaws.services.s3.transfer.Copy;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.TransferManagerBuilder;
import com.amazonaws.services.s3.transfer.Upload;

import javax.crypto.KeyGenerator;
import java.io.File;
import java.security.SecureRandom;

public class ServerSideEncryptionCopyObjectUsingHLwithSSEC {

    public static void main(String[] args) throws Exception {
        Regions clientRegion = Regions.DEFAULT_REGION;
        String bucketName = "*** Bucket name ***";
        String fileToUpload = "*** File path ***";
        String keyName = "*** New object key name ***";
        String targetKeyName = "*** Key name for object copy ***";

        try {
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .withRegion(clientRegion)
                    .withCredentials(new ProfileCredentialsProvider())
                    .build();
            TransferManager tm = TransferManagerBuilder.standard()
                    .withS3Client(s3Client)
                    .build();

            // Create an object from a file.
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, new File(fileToUpload));

            // Create an encryption key.
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(256, new SecureRandom());
            SSECustomerKey sseCustomerEncryptionKey = new SSECustomerKey(keyGenerator.generateKey());

            // Upload the object. TransferManager uploads asynchronously, so this call
            // returns immediately.
            putObjectRequest.setSSECustomerKey(sseCustomerEncryptionKey);
            Upload upload = tm.upload(putObjectRequest);

            // Optionally, wait for the upload to finish before continuing.
            upload.waitForCompletion();
            System.out.println("Object created.");

            // Copy the object and store the copy using SSE-C with a new key.
            CopyObjectRequest copyObjectRequest = new CopyObjectRequest(bucketName, keyName, bucketName, targetKeyName);
            SSECustomerKey sseTargetObjectEncryptionKey = new SSECustomerKey(keyGenerator.generateKey());
            copyObjectRequest.setSourceSSECustomerKey(sseCustomerEncryptionKey);
            copyObjectRequest.setDestinationSSECustomerKey(sseTargetObjectEncryptionKey);

            // Copy the object. TransferManager copies asynchronously, so this call returns
            // immediately.
            Copy copy = tm.copy(copyObjectRequest);

            // Optionally, wait for the upload to finish before continuing.
            copy.waitForCompletion();
            System.out.println("Copy complete.");
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
```

------
#### [ .NET ]

멀티파트 업로드 API를 사용하여 대형 객체를 업로드할 수 있습니다([Amazon S3에서 멀티파트 업로드를 사용한 객체 업로드 및 복사](mpuoverview.md) 참조). AWS SDK for .NET에서는 대형 객체를 업로드하는 상위 수준 또는 하위 수준의 API를 제공합니다. 이들 API는 요청의 암호화 관련 헤더를 지원합니다.
+ 상위 수준의 `Transfer-Utility `API를 사용할 때는 아래와 같이 `TransferUtilityUploadRequest`에 암호화 관련 헤더를 제공합니다. 코드 예제는 [멀티파트 업로드를 사용한 객체 업로드](mpu-upload-object.md) 단원을 참조하십시오.

  ```
  TransferUtilityUploadRequest request = new TransferUtilityUploadRequest()
  {
      FilePath = filePath,
      BucketName = existingBucketName,
      Key = keyName,
      // Provide encryption information.
      ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
      ServerSideEncryptionCustomerProvidedKey = base64Key,
  };
  ```
+ 하위 수준의 API를 사용할 경우 멀티파트 업로드 요청을 시작할 때 암호화 관련 정보를 제공하고, 이후 부분 업로드 요청 시에도 동일한 암호화 정보를 제공합니다. 멀티파트 업로드 완료 요청에서는 암호화 관련 헤더를 제공할 필요가 없습니다. 예를 보려면 [AWS SDK 사용(하위 수준 API)](mpu-upload-object.md#mpu-upload-low-level) 섹션을 참조하십시오.

  다음은 기존 대형 객체의 복사본을 만드는 하위 수준의 멀티파트 업로드 예제입니다. 이 예제에서 객체는 SSE-C를 사용하여 Amazon S3에 저장되고, 대상 객체 또한 SSE-C를 사용하여 저장됩니다. 예제에서는 다음을 수행합니다.
  + 암호화 키와 관련 정보를 제공하여 멀티파트 업로드 요청을 시작합니다.
  + `CopyPartRequest`에 원본 및 대상 객체 암호화 키와 관련 정보를 제공합니다.
  + 객체 메타데이터를 검색하여 복사할 원본 객체의 크기를 확인합니다.
  + 5MB 단위로 객체를 업로드합니다.  
**Example**  

  ```
  using Amazon;
  using Amazon.S3;
  using Amazon.S3.Model;
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Security.Cryptography;
  using System.Threading.Tasks;
  
  namespace Amazon.DocSamples.S3
  {
      class SSECLowLevelMPUcopyObjectTest
      {
          private const string existingBucketName = "*** bucket name ***";
          private const string sourceKeyName      = "*** source object key name ***"; 
          private const string targetKeyName      = "*** key name for the target object ***";
          private const string filePath           = @"*** file path ***";
          // Specify your bucket region (an example region is shown).
          private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2;
          private static IAmazonS3 s3Client;
          static void Main()
          {
              s3Client = new AmazonS3Client(bucketRegion);
              CopyObjClientEncryptionKeyAsync().Wait();
          }
  
          private static async Task CopyObjClientEncryptionKeyAsync()
          {
              Aes aesEncryption = Aes.Create();
              aesEncryption.KeySize = 256;
              aesEncryption.GenerateKey();
              string base64Key = Convert.ToBase64String(aesEncryption.Key);
  
              await CreateSampleObjUsingClientEncryptionKeyAsync(base64Key, s3Client);
  
              await CopyObjectAsync(s3Client, base64Key);
          }
          private static async Task CopyObjectAsync(IAmazonS3 s3Client, string base64Key)
          {
              List<CopyPartResponse> uploadResponses = new List<CopyPartResponse>();
  
              // 1. Initialize.
              InitiateMultipartUploadRequest initiateRequest = new InitiateMultipartUploadRequest
              {
                  BucketName = existingBucketName,
                  Key = targetKeyName,
                  ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                  ServerSideEncryptionCustomerProvidedKey = base64Key,
              };
  
              InitiateMultipartUploadResponse initResponse =
                  await s3Client.InitiateMultipartUploadAsync(initiateRequest);
  
              // 2. Upload Parts.
              long partSize = 5 * (long)Math.Pow(2, 20); // 5 MB
              long firstByte = 0;
              long lastByte = partSize;
  
              try
              {
                  // First find source object size. Because object is stored encrypted with
                  // customer provided key you need to provide encryption information in your request.
                  GetObjectMetadataRequest getObjectMetadataRequest = new GetObjectMetadataRequest()
                  {
                      BucketName = existingBucketName,
                      Key = sourceKeyName,
                      ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                      ServerSideEncryptionCustomerProvidedKey = base64Key // " * **source object encryption key ***"
                  };
  
                  GetObjectMetadataResponse getObjectMetadataResponse = await s3Client.GetObjectMetadataAsync(getObjectMetadataRequest);
  
                  long filePosition = 0;
                  for (int i = 1; filePosition < getObjectMetadataResponse.ContentLength; i++)
                  {
                      CopyPartRequest copyPartRequest = new CopyPartRequest
                      {
                          UploadId = initResponse.UploadId,
                          // Source.
                          SourceBucket = existingBucketName,
                          SourceKey = sourceKeyName,
                          // Source object is stored using SSE-C. Provide encryption information.
                          CopySourceServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                          CopySourceServerSideEncryptionCustomerProvidedKey = base64Key, //"***source object encryption key ***",
                          FirstByte = firstByte,
                          // If the last part is smaller then our normal part size then use the remaining size.
                          LastByte = lastByte > getObjectMetadataResponse.ContentLength ?
                              getObjectMetadataResponse.ContentLength - 1 : lastByte,
  
                          // Target.
                          DestinationBucket = existingBucketName,
                          DestinationKey = targetKeyName,
                          PartNumber = i,
                          // Encryption information for the target object.
                          ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                          ServerSideEncryptionCustomerProvidedKey = base64Key
                      };
                      uploadResponses.Add(await s3Client.CopyPartAsync(copyPartRequest));
                      filePosition += partSize;
                      firstByte += partSize;
                      lastByte += partSize;
                  }
  
                  // Step 3: complete.
                  CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest
                  {
                      BucketName = existingBucketName,
                      Key = targetKeyName,
                      UploadId = initResponse.UploadId,
                  };
                  completeRequest.AddPartETags(uploadResponses);
  
                  CompleteMultipartUploadResponse completeUploadResponse =
                      await s3Client.CompleteMultipartUploadAsync(completeRequest);
              }
              catch (Exception exception)
              {
                  Console.WriteLine("Exception occurred: {0}", exception.Message);
                  AbortMultipartUploadRequest abortMPURequest = new AbortMultipartUploadRequest
                  {
                      BucketName = existingBucketName,
                      Key = targetKeyName,
                      UploadId = initResponse.UploadId
                  };
                  s3Client.AbortMultipartUpload(abortMPURequest);
              }
          }
          private static async Task CreateSampleObjUsingClientEncryptionKeyAsync(string base64Key, IAmazonS3 s3Client)
          {
              // List to store upload part responses.
              List<UploadPartResponse> uploadResponses = new List<UploadPartResponse>();
  
              // 1. Initialize.
              InitiateMultipartUploadRequest initiateRequest = new InitiateMultipartUploadRequest
              {
                  BucketName = existingBucketName,
                  Key = sourceKeyName,
                  ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                  ServerSideEncryptionCustomerProvidedKey = base64Key
              };
  
              InitiateMultipartUploadResponse initResponse =
                 await s3Client.InitiateMultipartUploadAsync(initiateRequest);
  
              // 2. Upload Parts.
              long contentLength = new FileInfo(filePath).Length;
              long partSize = 5 * (long)Math.Pow(2, 20); // 5 MB
  
              try
              {
                  long filePosition = 0;
                  for (int i = 1; filePosition < contentLength; i++)
                  {
                      UploadPartRequest uploadRequest = new UploadPartRequest
                      {
                          BucketName = existingBucketName,
                          Key = sourceKeyName,
                          UploadId = initResponse.UploadId,
                          PartNumber = i,
                          PartSize = partSize,
                          FilePosition = filePosition,
                          FilePath = filePath,
                          ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
                          ServerSideEncryptionCustomerProvidedKey = base64Key
                      };
  
                      // Upload part and add response to our list.
                      uploadResponses.Add(await s3Client.UploadPartAsync(uploadRequest));
  
                      filePosition += partSize;
                  }
  
                  // Step 3: complete.
                  CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest
                  {
                      BucketName = existingBucketName,
                      Key = sourceKeyName,
                      UploadId = initResponse.UploadId,
                      //PartETags = new List<PartETag>(uploadResponses)
  
                  };
                  completeRequest.AddPartETags(uploadResponses);
  
                  CompleteMultipartUploadResponse completeUploadResponse =
                      await s3Client.CompleteMultipartUploadAsync(completeRequest);
  
              }
              catch (Exception exception)
              {
                  Console.WriteLine("Exception occurred: {0}", exception.Message);
                  AbortMultipartUploadRequest abortMPURequest = new AbortMultipartUploadRequest
                  {
                      BucketName = existingBucketName,
                      Key = sourceKeyName,
                      UploadId = initResponse.UploadId
                  };
                  await s3Client.AbortMultipartUploadAsync(abortMPURequest);
              }
          }
      }
  }
  ```

------

# 범용 버킷에 대한 SSE-C 차단 또는 차단 해제
<a name="blocking-unblocking-s3-c-encryption-gpb"></a>

Amazon S3 관리형 키(SSE-S3) 또는 AWS KMS 키를 사용한 서버 측 암호화(SSE-KMS)의 유연성이 부족하기 때문에 Amazon S3의 최신 사용 사례에서는 더 이상 고객 제공 키를 사용한 서버 측 암호화(SSE-C)를 사용하지 않습니다. SSE-C는 SSE-C 암호화 데이터와 상호 작용할 때마다 암호화 키를 제공해야 하므로 SSE-C 키를 S3 버킷에서 데이터를 읽는 다른 사용자, 역할 또는 AWS 서비스와 공유하여 데이터를 운영할 수 없습니다.

범용 버킷에서 사용할 수 있는 서버 측 암호화 유형을 제한하려면 버킷의 기본 암호화 구성을 업데이트하여 SSE-C 쓰기 요청을 차단하도록 선택할 수 있습니다. 이 버킷 수준 구성은 SSE-C를 지정하는 객체 업로드 요청을 차단합니다. 버킷에 대해 SSE-C가 차단되면 SSE-C 암호화를 지정하는 모든 `PutObject`, `CopyObject`, `PostObject` 또는 멀티파트 업로드 또는 복제 요청이 HTTP 403 `AccessDenied` 오류와 함께 거부됩니다.

이 설정은 `PutBucketEncryption` API의 파라미터이며 `s3:PutEncryptionConfiguration` 권한이 있는 경우 S3 콘솔, AWS CLI 및 AWS SDK를 사용하여 업데이트할 수도 있습니다.

유효한 값은 범용 버킷에 대한 SSE-C 암호화를 차단하는 `SSE-C`와 버킷에 대한 쓰기에 SSE-C를 사용하도록 허용하는 `NONE`입니다.

**중요**  
2026년 4월부터 AWS는 모든 새 버킷에 대해 고객 제공 키를 사용한 서버 측 암호화(SSE-C)를 비활성화합니다. 또한 SSE-C 암호화 데이터가 없는 AWS 계정의 모든 기존 버킷에 대해 SSE-C 암호화가 비활성화됩니다. 이러한 변경으로 인해 SSE-C 암호화가 필요한 몇 가지 애플리케이션은 버킷을 생성한 후 [https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html) API를 통해 SSE-C 사용을 의도적으로 활성화해야 합니다. 이러한 경우 자동화 스크립트,CloudFormation 템플릿 또는 기타 인프라 구성 도구를 업데이트하여 해당 설정을 구성해야 할 수 있습니다. 자세한 내용은 [AWS 스토리지 블로그 게시물](https://aws.amazon.com/blogs/storage/advanced-notice-amazon-s3-to-disable-the-use-of-sse-c-encryption-by-default-for-all-new-buckets-and-select-existing-buckets-in-april-2026/)을 참조하세요.

## 권한
<a name="bucket-encryption-permissions"></a>

`PutBucketEncryption` API 또는 S3 콘솔, AWS SDK 또는 AWS CLI를 사용하여 범용 버킷의 암호화 유형을 차단하거나 차단 해제합니다. 이 경우 다음 권한이 있어야 합니다.
+ `s3:PutEncryptionConfiguration`

`GetBucketEncryption` API 또는 S3 콘솔, AWS SDK 또는 AWS CLI를 사용하여 범용 버킷에 대해 차단된 암호화 유형을 봅니다. 이 경우 다음 권한이 있어야 합니다.
+ `s3:GetEncryptionConfiguration`

## SSE-C 암호화 차단 전 고려 사항
<a name="considerations-before-blocking-sse-c"></a>

버킷에 대해 SSE-C를 차단하면 다음 암호화 동작이 적용됩니다.
+ 차단된 SSE-C 암호화 전에 버킷에 있었던 객체의 암호화는 변경되지 않습니다.
+ SSE-C 암호화를 차단한 후에는 요청에 필요한 SSE-C 헤더를 제공하는 한 SSE-C로 암호화된 기존 객체에 대해 GetObject 및 HeadObject 요청을 계속 수행할 수 있습니다.
+ 버킷에 대해 SSE-C가 차단되면 SSE-C 암호화를 지정하는 모든 `PutObject`, `CopyObject`, `PostObject` 또는 멀티파트 업로드 요청이 HTTP 403 `AccessDenied` 오류와 함께 거부됩니다.
+ 복제 대상 버킷에 SSE-C가 차단되어 있고 복제되는 소스 객체가 SSE-C로 암호화된 경우 HTTP 403 `AccessDenied` 오류와 함께 복제가 실패합니다.

이 암호화 유형을 차단하기 전에 버킷에서 SSE-C 암호화를 사용하는지 검토하려면 [AWS CloudTrail](https://aws.amazon.com/cloudtrail/)과 같은 도구를 사용하여 데이터에 대한 액세스를 모니터링할 수 있습니다. 이 [블로그 게시물](https://aws.amazon.com/blogs/storage/auditing-amazon-s3-server-side-encryption-methods-for-object-uploads/)은 객체 업로드에 대한 암호화 방법을 실시간으로 감사하는 방법을 보여줍니다. 또한 이 [re:Post 문서를](https://repost.aws/articles/ARhGC12rOiTBCKHcAe9GZXCA/how-to-detect-existing-use-of-sse-c-in-your-amazon-s3-buckets) 참조하여 S3 인벤토리 보고서 쿼리를 통해 SSE-C 암호화 객체가 있는지 확인할 수 있습니다.

### 단계
<a name="block-sse-c-gpb-steps"></a>

Amazon S3 콘솔, AWS Command Line Interface(AWS CLI), Amazon S3 REST API 및 AWS SDK를 사용하여 범용 버킷에 대해 고객 제공 키를 사용한 서버 측 암호화(SSE-C)를 차단하거나 차단 해제할 수 있습니다.

### S3 콘솔 사용
<a name="block-sse-c-gpb-console"></a>

Amazon S3 콘솔을 사용하여 버킷에 대한 SSE-C 암호화를 차단하거나 차단 해제하려면 다음을 수행합니다.

1. AWS Management Console에 로그인하고 https://console.aws.amazon.com/s3/ 페이지에서 Amazon S3 콘솔을 엽니다.

1. 왼쪽 탐색 창에서 **범용 버킷**을 선택합니다.

1. SSE-C 암호화를 차단하려는 버킷을 선택합니다.

1. 버킷의 **속성** 탭을 선택합니다.

1. 버킷의 **기본 암호화** 속성 패널로 이동하여 **편집**을 선택합니다.

1. **차단된 암호화 유형** 섹션에서 **고객 제공 키를 사용한 서버 측 암호화(SSE-C)** 옆의 확인란을 선택하여 SSE-C 암호화를 차단하거나 이 확인란을 선택 취소하여 SSE-C를 허용합니다.

1. **변경 사항 저장**을 선택합니다.

### AWS CLI 사용
<a name="block-sse-c-gpb-cli"></a>

AWS CLI를 설치하려면 *AWS Command Line Interface 사용 설명서*에서 [AWS 설치](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)를 참조하세요.

다음 CLI 예제에서는 AWS CLI를 사용하여 범용 버킷에 대한 SSE-C 암호화를 차단하거나 차단 해제하는 방법을 보여줍니다. 명령을 사용하려면 *사용자 입력 자리 표시자*를 사용자의 정보로 대체합니다.

**범용 버킷에 대한 SSE-C 암호화 차단 요청:**

```
aws s3api put-bucket-encryption \
  --bucket amzn-s3-demo-bucket \
  --server-side-encryption-configuration '{
    "Rules": [{
      "BlockEncryptionTypes": {
        "EncryptionType": "SSE-C"
      }
    }]
  }'
```

**범용 버킷에서 SSE-C 암호화 사용 활성화 요청:**

```
aws s3api put-bucket-encryption \
  --bucket amzn-s3-demo-bucket \
  --server-side-encryption-configuration '{
    "Rules": [{
      "BlockEncryptionTypes": {
        "EncryptionType": "NONE"
      }
    }]
  }'
```

## AWS SDK 사용
<a name="block-sse-c-gpb-sdks"></a>

------
#### [ SDK for Java 2.x ]

다음 CLI 예제에서는 AWS SDK를 사용하여 범용 버킷에 대한 SSE-C 암호화 쓰기를 차단하거나 차단 해제하는 방법을 보여줍니다.

**예 - 기본 암호화 구성을 SSE-S3로 설정하고 SSE-C를 차단하는 PutBucketEncryption 요청**

```
S3Client s3Client = ...;
ServerSideEncryptionByDefault defaultSse = ServerSideEncryptionByDefault
        .builder()
        .sseAlgorithm(ServerSideEncryption.AES256)
        .build();
BlockedEncryptionTypes blockedEncryptionTypes = BlockedEncryptionTypes
        .builder()
        .encryptionType(EncryptionType.SSE_C)
        .build();
ServerSideEncryptionRule rule = ServerSideEncryptionRule.builder()
        .applyServerSideEncryptionByDefault(defaultSse)
        .blockedEncryptionTypes(blockedEncryptionTypes)
        .build();
s3Client.putBucketEncryption(be -> be
        .bucket(bucketName)
        .serverSideEncryptionConfiguration(c -> c.rules(rule)));
```

**예 - 기본 암호화 구성을 SSE-S3로 설정하고 SSE-C를 차단 해제하는 PutBucketEncryption 요청**

```
S3Client s3Client = ...;
ServerSideEncryptionByDefault defaultSse = ServerSideEncryptionByDefault
        .builder()
        .sseAlgorithm(ServerSideEncryption.AES256)
        .build();
BlockedEncryptionTypes blockedEncryptionTypes = BlockedEncryptionTypes
        .builder()
        .encryptionType(EncryptionType.NONE)
        .build();
ServerSideEncryptionRule rule = ServerSideEncryptionRule.builder()
        .applyServerSideEncryptionByDefault(defaultSse)
        .blockedEncryptionTypes(blockedEncryptionTypes)
        .build();
s3Client.putBucketEncryption(be -> be
        .bucket(bucketName)
        .serverSideEncryptionConfiguration(c -> c.rules(rule)));
```

------
#### [ SDK for Python Boto3 ]

**예 - 기본 암호화 구성을 SSE-S3로 설정하고 SSE-C를 차단하는 PutBucketEncryption 요청**

```
s3 = boto3.client("s3")
s3.put_bucket_encryption(
    Bucket="amzn-s3-demo-bucket",
    ServerSideEncryptionConfiguration={
        "Rules":[{
            "ApplyServerSideEncryptionByDefault": {
                "SSEAlgorithm": "AES256"
            },
            "BlockedEncryptionTypes": {
                "EncryptionType": ["SSE-C"]
            }
        }]
    }
)
```

**예 - 기본 암호화 구성을 SSE-S3로 설정하고 SSE-C를 차단 해제하는 PutBucketEncryption 요청**

```
s3 = boto3.client("s3")
s3.put_bucket_encryption(
    Bucket="amzn-s3-demo-bucket",
    ServerSideEncryptionConfiguration={
        "Rules":[{
            "ApplyServerSideEncryptionByDefault": {
                "SSEAlgorithm": "AES256"
            },
            "BlockedEncryptionTypes": {
                "EncryptionType": ["NONE"]
            }
        }]
    }
)
```

------

## REST API 사용
<a name="bucket-tag-add-api"></a>

범용 버킷에 대한 SSE-C 암호화를 차단 또는 차단 해제하기 위한 Amazon S3 REST API 지원에 대한 자세한 내용은 *Amazon Simple Storage Service API 참조*의 다음 섹션을 참조하세요.
+ [PutBucketEncryption](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html) 및 [GetBucketEncryption](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketEncryption.html) API 작업의 [ServerSideEncryptionRule](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ServerSideEncryptionRule.html) 데이터 형식에 사용되는 [BlockedEncryptionTypes](https://docs.aws.amazon.com/AmazonS3/latest/API/API_BlockedEncryptionTypes.html) 데이터 형식입니다.

# 새 버킷의 기본 SSE-C 설정 FAQ
<a name="default-s3-c-encryption-setting-faq"></a>

**중요**  
2026년 4월부터 AWS는 모든 새 버킷에 대해 고객 제공 키를 사용한 서버 측 암호화(SSE-C)를 비활성화합니다. 또한 SSE-C 암호화 데이터가 없는 AWS 계정의 모든 기존 버킷에 대해 SSE-C 암호화가 비활성화됩니다. 이러한 변경으로 인해 SSE-C 암호화가 필요한 몇 가지 애플리케이션은 버킷을 생성한 후 [https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html) API를 통해 SSE-C 사용을 의도적으로 활성화해야 합니다. 이러한 경우 자동화 스크립트,CloudFormation 템플릿 또는 기타 인프라 구성 도구를 업데이트하여 해당 설정을 구성해야 할 수 있습니다. 자세한 내용은 [AWS 스토리지 블로그 게시물](https://aws.amazon.com/blogs/storage/advanced-notice-amazon-s3-to-disable-the-use-of-sse-c-encryption-by-default-for-all-new-buckets-and-select-existing-buckets-in-april-2026/)을 참조하세요.

다음 섹션에서는 이 업데이트에 대한 질문과 답변을 제공합니다.

**1. 2026년 4월에 새 SSE-C 설정이 새로 생성된 모든 버킷에 적용되나요?**

예. 2026년 4월 중에 새로운 기본 설정은 모든 AWS 리전에 점진적으로 적용될 예정입니다.

**2. 이 업데이트가 모든 AWS 리전에 출시되려면 얼마나 걸리나요?**

이 업데이트는 출시되는 데 몇 주가 걸릴 것입니다. 이 업데이트를 배포하기 시작하면 '새로운 소식' 게시물을 게시할 예정입니다.

**3. 업데이트가 완료되었는지 어떻게 알 수 있나요?**

새 버킷을 생성하고 [GetBucketEncryption](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketEncryption.html) API 작업을 직접 호출해 SSE-C 암호화가 비활성화되었는지 확인하여 AWS 리전에서 변경이 완료되었는지 쉽게 확인할 수 있습니다. 업데이트가 완료되면 모든 새 범용 버킷에는 기본적으로 SSE-C 암호화가 비활성화됩니다. [PutBucketEncryption](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html) API 작업을 직접 호출하여 S3 버킷을 생성한 후 이러한 설정을 조정할 수 있습니다.

**4. Amazon S3에서 기존 버킷 구성을 업데이트하나요?**

AWS 계정에 SSE-C 암호화 객체가 없는 경우 AWS는 모든 기존 버킷에서 SSE-C 암호화를 비활성화합니다. AWS 계정의 버킷에 SSE-C 암호화 객체가 있는 경우 AWS는 해당 계정의 버킷에 대한 버킷 구성을 변경하지 않습니다. AWS 리전에 대한 `CreateBucket` 변경이 완료되면 새 기본 설정이 모든 새 범용 버킷에 적용됩니다.

 **5. 업데이트가 완료되기 전에 버킷에 대한 SSE-C 암호화를 비활성화할 수 있나요?**

예. [PutBucketEncryption](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html) API 작업을 직접 호출하고 새 `BlockedEncryptionTypes` 헤더를 지정하여 모든 버킷에 대한 SSE-C 암호화를 비활성화할 수 있습니다.

**6. SSE-C를 사용하여 새 버킷의 데이터를 암호화할 수 있나요?**

예. Amazon S3 관리형 키(SSE-S3) 또는 AWS KMS 키를 사용한 서버 측 암호화(SSE-KMS)의 유연성이 부족하기 때문에 Amazon S3의 최신 사용 사례에서는 더 이상 SSE-C를 사용하지 않습니다. 새 버킷에서 SSE-C 암호화를 사용해야 하는 경우 새 버킷을 생성한 다음 별도의 `PutBucketEncryption` 요청에서 SSE-C 암호화 사용을 활성화할 수 있습니다.

 **예제**

```
aws s3api create-bucket \  
bucket amzn-s3-demo-bucket \ 
region us-east-1 \ 
  
aws s3api put-bucket-encryption \  
-- bucket amzn-s3-demo-bucket \
-- server-side-encryption-configuration \
'{ \Rules\: [{   
   {   
   \ApplyServerSideEncryptionByDefault\: {   
     \SSEAlgorithm\: \AES256\,  
    },   
   \BlockedEncryptionTypes\: [  
     \EncryptionType\:\NONE\]   
   }   
   }]   
}'
```

**참고**  
`PutBucketEncryption` API를 직접 호출할 `s3:PutEncryptionConfiguration` 권한이 있어야 합니다.

**7. SSE-C를 차단하면 버킷에 대한 요청에 어떤 영향을 미치나요?**

버킷에 대해 SSE-C가 차단되면 SSE-C 암호화를 지정하는 모든 `PutObject`, `CopyObject`, `PostObject` 또는 멀티파트 업로드 또는 복제 요청이 HTTP 403 `AccessDenied` 오류와 함께 거부됩니다.