1
+ #
2
+ import datetime
3
+ import hashlib
4
+ import hmac
5
+ import requests
6
+ from requests .utils import quote
7
+
8
+ def generate_aws_signed_url (region , bucket , object_key , access_key , secret_key , expiration , endpoint = None ):
9
+
10
+ # request elements
11
+ http_method = 'GET'
12
+ endpoint = endpoint if endpoint else 's3.amazonaws.com'
13
+ host = bucket + '.' + endpoint
14
+ endpoint = 'https://' + host
15
+
16
+ # hashing methods
17
+ def hash (key , msg ):
18
+ return hmac .new (key , msg .encode ('utf-8' ), hashlib .sha256 ).digest ()
19
+
20
+ # region is a wildcard value that takes the place of the AWS region value
21
+ # as COS doen't use regions like AWS, this parameter can accept any string
22
+ def createSignatureKey (key , datestamp , region , service ):
23
+ keyDate = hash (('AWS4' + key ).encode ('utf-8' ), datestamp )
24
+ keyRegion = hash (keyDate , region )
25
+ keyService = hash (keyRegion , service )
26
+ keySigning = hash (keyService , 'aws4_request' )
27
+ return keySigning
28
+
29
+ # assemble the standardized request
30
+ time = datetime .datetime .utcnow ()
31
+ timestamp = time .strftime ('%Y%m%dT%H%M%SZ' )
32
+ datestamp = time .strftime ('%Y%m%d' )
33
+
34
+ standardized_querystring = ('X-Amz-Algorithm=AWS4-HMAC-SHA256' +
35
+ '&X-Amz-Credential=' + access_key + '/' + datestamp + '/' + region + '/s3/aws4_request' +
36
+ '&X-Amz-Date=' + timestamp +
37
+ '&X-Amz-Expires=' + str (expiration ) +
38
+ '&X-Amz-SignedHeaders=host' )
39
+ standardized_querystring_url_encoded = quote (standardized_querystring , safe = '&=' )
40
+
41
+ standardized_resource = '/' + object_key
42
+ standardized_resource_url_encoded = quote (standardized_resource , safe = '&' )
43
+
44
+ payload_hash = 'UNSIGNED-PAYLOAD'
45
+ standardized_headers = 'host:' + host
46
+ signed_headers = 'host'
47
+
48
+ standardized_request = (http_method + '\n ' +
49
+ standardized_resource + '\n ' +
50
+ standardized_querystring_url_encoded + '\n ' +
51
+ standardized_headers + '\n ' +
52
+ '\n ' +
53
+ signed_headers + '\n ' +
54
+ payload_hash ).encode ('utf-8' )
55
+
56
+ # assemble string-to-sign
57
+ hashing_algorithm = 'AWS4-HMAC-SHA256'
58
+ credential_scope = datestamp + '/' + region + '/' + 's3' + '/' + 'aws4_request'
59
+ sts = (hashing_algorithm + '\n ' +
60
+ timestamp + '\n ' +
61
+ credential_scope + '\n ' +
62
+ hashlib .sha256 (standardized_request ).hexdigest ())
63
+
64
+ # generate the signature
65
+ signature_key = createSignatureKey (secret_key , datestamp , region , 's3' )
66
+ signature = hmac .new (signature_key ,
67
+ (sts ).encode ('utf-8' ),
68
+ hashlib .sha256 ).hexdigest ()
69
+
70
+ # create and send the request
71
+ # the 'requests' package autmatically adds the required 'host' header
72
+ request_url = (endpoint + '/' +
73
+ object_key + '?' +
74
+ standardized_querystring_url_encoded +
75
+ '&X-Amz-Signature=' +
76
+ signature )
77
+
78
+ def hex_hash (key , msg ):
79
+ return hmac .new (b'key' , msg .encode ('utf-8' ), hashlib .sha256 ).hexdigest ()
80
+
81
+ def createHexSignatureKey (key , datestamp , region , service ):
82
+ keyDate = hex_hash (('AWS4' + key ).encode ('utf-8' ), datestamp )
83
+ keyRegion = hex_hash (keyDate , region )
84
+ keyService = hex_hash (keyRegion , service )
85
+ keySigning = hex_hash (keyService , 'aws4_request' )
86
+ return keySigning
87
+
88
+ signature_key_hex = createHexSignatureKey (secret_key , datestamp , region , 's3' )
89
+
90
+ # print(request_url)
91
+ return request_url
0 commit comments