AWS Signature Version 4 (AWS4)

紀錄一下計算Signature的部分. 依序的步驟如下, 便可以計算出 signature.

1) canonical request

Canonical_Request =
  • HTTP_Request_Method + '\n'
  • Canonical_URI + '\n'
  • Canonical_Query_String + '\n'
  • Canonical_Headers + '\n'
  • Signed_Headers + '\n'
  • HexEncode(Hash(RequestPayload))
補充:
url & query的部分是需要url encoded, 範例如下:
Canonical_URI:
encoded => /asustor-test/s3/upload/%E4%BA%BA
original => /asustor-test/s3/upload/人)
Canonical_Query_String:
encoded => delimiter=%2F&prefix=s3%2Fupload%2Ftest%2F
original => delimiter=/&prefix=s3/upload/test/)

2) string to sign

StringToSign =
  • Algorithm + '\n'
  • RequestDate + '\n'
  • CredentialScope + '\n'
  • Hashed(Canonical_Request))

補充:
RequestDate為ISO8601 Basic format (YYYYMMDD'T'HHMMSS'Z')

3) signing key

這邊主要是把secret access key 和 CredentialScope結合起來計算出signing key.
(e.g. Credential Scope為20110909/us-east-1/iam/aws4_request)

  • kSecret = Your AWS Secret Access Key
  • kDate = HMAC("AWS4" + kSecret, Date)
  • kRegion = HMAC(kDate, Region)
  • kService = HMAC(kRegion, Service)
  • kSigning = HMAC(kService, "aws4_request")

4) signature

signature =
  • HexEncode(HMAC( kSigning , StringToSign ))

Example

import hashlib
import hmac

def create_canonical_form(canonical_paras):
    canonical_form = canonical_paras['http_method'] + '\n' +  canonical_paras['canonical_uri'] + '\n' +  canonical_paras['canonical_query'] + '\n' +  canonical_paras['canonical_headers'] + '\n' +  canonical_paras['canonical_signed'] + '\n' +  canonical_paras['hash_payload']
    return canonical_form

def stringtosign(algorithm, req_date, credential_scope, hash_canonical_form):
    stringtosignstr = algorithm + '\n' + req_date + '\n' +  credential_scope + '\n' + hash_canonical_form
    return stringtosignstr

def get_signing_key(secretkey, date, region, service, encryptedreq):
    ksecret = "AWS4%s" % (secretkey)
    kdate = hmac.new(ksecret.encode('utf-8'), date.encode('utf-8'), hashlib.sha256).digest()
    kregion = hmac.new(kdate, region.encode('utf-8'), hashlib.sha256).digest()
    kservice = hmac.new(kregion, service.encode('utf-8'), hashlib.sha256).digest()
    ksigning = hmac.new(kservice, encryptedreq.encode('utf-8'), hashlib.sha256).digest()
    return ksigning

def test_case():
    '''
    <= canonical form =>
    POST
    /

    content-type:application/x-www-form-urlencoded; charset=utf-8
    host:iam.amazonaws.com
    x-amz-date:20110909T233600Z

    content-type;host;x-amz-date
    b6359072c78d70ebee1e81adcbab4f01bf2c23245fa365ef83fe8f1f955085e2
    <= string to sign =>
    AWS4-HMAC-SHA256
    20110909T233600Z
    20110909/us-east-1/iam/aws4_request
    3511de7e95d28ecd39e9513b642aee07e54f4941150d8df8bf94b328ef7e55e2
    <= signature =>
    ced6826de92d2bdeed8f846f0bf508e8559e98e4b0199114b84c54174deb456c
    '''
    hashpaylod = hashlib.new('sha256')
    hashpaylod.update(b"Action=ListUsers&Version=2010-05-08")
    paras = { "http_method":"POST"
            , "canonical_uri":"/"
            , "canonical_query":""
            , "canonical_headers":"content-type:application/x-www-form-urlencoded; charset=utf-8\nhost:iam.amazonaws.com\nx-amz-date:20110909T233600Z\n"
            , "canonical_signed":"content-type;host;x-amz-date"
            , "hash_payload":(hashpaylod.hexdigest())}

    canonicalstr = create_canonical_form(paras)
    print("===canoncail form===\n{form}".format(form=canonicalstr))

    hashcanonicalform = hashlib.new('sha256')
    hashcanonicalform.update(canonicalstr.encode('utf-8'))
    szstrtosign = stringtosign("AWS4-HMAC-SHA256", "20110909T233600Z", "20110909/us-east-1/iam/aws4_request", hashcanonicalform.hexdigest())
    print("===string to sign===\n{strtosign}".format(strtosign=szstrtosign))

    signingkey = get_signing_key("wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", "20110909", "us-east-1", "iam", "aws4_request")
    signature = hmac.new(signingkey, (szstrtosign).encode('utf-8'), hashlib.sha256)
    print("===signature===\n{signature}".format(signature=signature.hexdigest()))

if __name__ == '__main__':
    test_case()

Reference

留言

這個網誌中的熱門文章

yocto recipe : (1) 撰寫 recipe

yocto recipe : (2) 撰寫 bbappend

yocto recipe : (3) 使用 External Source 來編譯軟體