Skip to content

Commit 2ddc6fd

Browse files
committed
add support of aws server-side encryption with customer-provided encryption keys (SSE-C)
Signed-off-by: wangyunqing <[email protected]>
1 parent c8de951 commit 2ddc6fd

File tree

4 files changed

+36
-5
lines changed

4 files changed

+36
-5
lines changed

S3/Config.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class Config(object):
9393
host_base = u"s3.amazonaws.com"
9494
host_bucket = u"%(bucket)s.s3.amazonaws.com"
9595
kms_key = u"" #can't set this and Server Side Encryption at the same time
96+
customer_key = u""
9697
# simpledb_host looks useless, legacy? to remove?
9798
simpledb_host = u"sdb.amazonaws.com"
9899
cloudfront_host = u"cloudfront.amazonaws.com"
@@ -247,8 +248,10 @@ def __init__(self, configfile = None, access_key=None, secret_key=None, access_t
247248
self.role_config()
248249

249250
#TODO check KMS key is valid
250-
if self.kms_key and self.server_side_encryption == True:
251-
warning('Cannot have server_side_encryption (S3 SSE) and KMS_key set (S3 KMS). KMS encryption will be used. Please set server_side_encryption to False')
251+
if (self.kms_key and self.server_side_encryption == True) or \
252+
(self.kms_key and self.customer_key) or \
253+
(self.customer_key and self.server_side_encryption == True):
254+
warning('Cannot have server_side_encryption (S3 SSE) and KMS_key set (S3 KMS) and server_side_encryption_customer (S3 SSE-C). KMS encryption will be used. Please set one')
252255
if self.kms_key and self.signature_v2 == True:
253256
raise Exception('KMS encryption requires signature v4. Please set signature_v2 to False')
254257

S3/MultiPart.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ def upload_part(self, seq, offset, chunk_size, labels, buffer = '', remote_statu
167167
warning("MultiPart: size (%d vs %d) does not match for %s part %d, reuploading."
168168
% (int(remote_status['size']), chunk_size, self.uri, seq))
169169

170-
headers = { "content-length": str(chunk_size) }
170+
headers = self.headers_baseline
171+
headers["content-length"] = str(chunk_size)
171172
query_string_params = {'partNumber':'%s' % seq,
172173
'uploadId': self.upload_id}
173174
request = self.s3.create_request("OBJECT_PUT", uri = self.uri,
@@ -190,7 +191,8 @@ def complete_multipart_upload(self):
190191
parts_xml.append(part_xml % (seq, etag))
191192
body = "<CompleteMultipartUpload>%s</CompleteMultipartUpload>" % ("".join(parts_xml))
192193

193-
headers = { "content-length": str(len(body)) }
194+
headers = self.headers_baseline
195+
headers["content-length"] = str(len(body))
194196
request = self.s3.create_request("OBJECT_POST", uri = self.uri,
195197
headers = headers, body = body,
196198
uri_params = {'uploadId': self.upload_id})

S3/S3.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,12 @@ def object_put(self, filename, uri, extra_headers = None, extra_label = ""):
664664
headers['x-amz-server-side-encryption'] = 'aws:kms'
665665
headers['x-amz-server-side-encryption-aws-kms-key-id'] = self.config.kms_key
666666

667+
## Set server side encryption customer
668+
if self.config.customer_key:
669+
headers["x-amz-server-side-encryption-customer-algorithm"] = "AES256"
670+
headers["x-amz-server-side-encryption-customer-key"] = base64.b64encode(self.config.customer_key)
671+
headers["x-amz-server-side-encryption-customer-key-MD5"] = compute_content_md5(self.config.customer_key)
672+
667673
## MIME-type handling
668674
headers["content-type"] = self.content_type(filename=filename)
669675

@@ -721,7 +727,14 @@ def object_put(self, filename, uri, extra_headers = None, extra_label = ""):
721727
def object_get(self, uri, stream, dest_name, start_position = 0, extra_label = ""):
722728
if uri.type != "s3":
723729
raise ValueError("Expected URI type 's3', got '%s'" % uri.type)
724-
request = self.create_request("OBJECT_GET", uri = uri)
730+
731+
headers = SortedDict(ignore_case = True)
732+
if self.config.customer_key:
733+
headers["x-amz-server-side-encryption-customer-algorithm"] = "AES256"
734+
headers["x-amz-server-side-encryption-customer-key"] = base64.b64encode(self.config.customer_key)
735+
headers["x-amz-server-side-encryption-customer-key-MD5"] = compute_content_md5(self.config.customer_key)
736+
737+
request = self.create_request("OBJECT_GET", uri = uri, headers = headers)
725738
labels = { 'source' : uri.uri(), 'destination' : dest_name, 'extra' : extra_label }
726739
response = self.recv_file(request, stream, labels, start_position)
727740
return response
@@ -843,6 +856,12 @@ def object_copy(self, src_uri, dst_uri, extra_headers = None):
843856
headers['x-amz-server-side-encryption'] = 'aws:kms'
844857
headers['x-amz-server-side-encryption-aws-kms-key-id'] = self.config.kms_key
845858

859+
## Set server side encryption customer
860+
if self.config.customer_key:
861+
headers["x-amz-server-side-encryption-customer-algorithm"] = "AES256"
862+
headers["x-amz-server-side-encryption-customer-key"] = base64.b64encode(self.config.customer_key)
863+
headers["x-amz-server-side-encryption-customer-key-MD5"] = compute_content_md5(self.config.customer_key)
864+
846865
if extra_headers:
847866
headers.update(extra_headers)
848867

@@ -900,6 +919,12 @@ def object_modify(self, src_uri, dst_uri, extra_headers = None):
900919
headers['x-amz-server-side-encryption'] = 'aws:kms'
901920
headers['x-amz-server-side-encryption-aws-kms-key-id'] = self.config.kms_key
902921

922+
## Set server side encryption customer
923+
if self.config.customer_key:
924+
headers["x-amz-server-side-encryption-customer-algorithm"] = "AES256"
925+
headers["x-amz-server-side-encryption-customer-key"] = base64.b64encode(self.config.customer_key)
926+
headers["x-amz-server-side-encryption-customer-key-MD5"] = compute_content_md5(self.config.customer_key)
927+
903928
if extra_headers:
904929
headers.update(extra_headers)
905930

s3cmd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2717,6 +2717,7 @@ def main():
27172717

27182718
optparser.add_option( "--server-side-encryption", dest="server_side_encryption", action="store_true", help="Specifies that server-side encryption will be used when putting objects. [put, sync, cp, modify]")
27192719
optparser.add_option( "--server-side-encryption-kms-id", dest="kms_key", action="store", help="Specifies the key id used for server-side encryption with AWS KMS-Managed Keys (SSE-KMS) when putting objects. [put, sync, cp, modify]")
2720+
optparser.add_option( "--server-side-encryption-customer-key", dest="customer_key", action="store", help="Specifies the key used for server-side encryption with customer-provided encryption keys (SSE-C) when putting objects or get SSE-C object. [put, sync, cp, modify, get]")
27202721

27212722
optparser.add_option( "--encoding", dest="encoding", metavar="ENCODING", help="Override autodetected terminal and filesystem encoding (character set). Autodetected: %s" % autodetected_encoding)
27222723
optparser.add_option( "--add-encoding-exts", dest="add_encoding_exts", metavar="EXTENSIONs", help="Add encoding to these comma delimited extensions i.e. (css,js,html) when uploading to S3 )")

0 commit comments

Comments
 (0)