@@ -55,6 +55,7 @@ static const char* X_AMZ_SIGNATURE = "X-Amz-Signature";
55
55
static const char * SIGNING_KEY = " AWS4" ;
56
56
static const char * LONG_DATE_FORMAT_STR = " %Y%m%dT%H%M%SZ" ;
57
57
static const char * SIMPLE_DATE_FORMAT_STR = " %Y%m%d" ;
58
+ static const char * EMPTY_STRING_SHA256 = " e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" ;
58
59
59
60
static const char * v4LogTag = " AWSAuthV4Signer" ;
60
61
@@ -131,6 +132,8 @@ AWSAuthV4Signer::AWSAuthV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvi
131
132
m_signPayloads(signPayloads),
132
133
m_urlEscapePath(urlEscapePath)
133
134
{
135
+ // go ahead and warm up the signing cache.
136
+ ComputeLongLivedHash (credentialsProvider->GetAWSCredentials ().GetAWSSecretKey (), DateTime::CalculateGmtTimestampAsString (SIMPLE_DATE_FORMAT_STR));
134
137
}
135
138
136
139
AWSAuthV4Signer::~AWSAuthV4Signer ()
@@ -322,45 +325,9 @@ Aws::String AWSAuthV4Signer::GenerateSignature(const AWSCredentials& credentials
322
325
323
326
Aws::StringStream ss;
324
327
325
- // now we do the complicated part of deriving a signing key.
326
- Aws::String signingKey (SIGNING_KEY);
327
- signingKey.append (credentials.GetAWSSecretKey ());
328
-
329
- // we use digest only for the derivation process.
330
- auto hashResult = m_HMAC->Calculate (ByteBuffer ((unsigned char *)simpleDate.c_str (), simpleDate.length ()),
331
- ByteBuffer ((unsigned char *)signingKey.c_str (), signingKey.length ()));
332
- if (!hashResult.IsSuccess ())
333
- {
334
- AWS_LOGSTREAM_ERROR (v4LogTag, " Failed to hmac (sha256) date string \" " << simpleDate << " \" " );
335
- return " " ;
336
- }
337
-
338
- auto kDate = hashResult.GetResult ();
339
- hashResult = m_HMAC->Calculate (ByteBuffer ((unsigned char *)m_region.c_str (), m_region.length ()), kDate );
340
- if (!hashResult.IsSuccess ())
341
- {
342
- AWS_LOGSTREAM_ERROR (v4LogTag, " Failed to hmac (sha256) region string \" " << m_region << " \" " );
343
- return " " ;
344
- }
345
-
346
- auto kRegion = hashResult.GetResult ();
347
- hashResult = m_HMAC->Calculate (ByteBuffer ((unsigned char *)m_serviceName.c_str (), m_serviceName.length ()), kRegion );
348
- if (!hashResult.IsSuccess ())
349
- {
350
- AWS_LOGSTREAM_ERROR (v4LogTag, " Failed to hmac (sha256) service string \" " << m_serviceName << " \" " );
351
- return " " ;
352
- }
353
-
354
- auto kService = hashResult.GetResult ();
355
- hashResult = m_HMAC->Calculate (ByteBuffer ((unsigned char *)AWS4_REQUEST, strlen (AWS4_REQUEST)), kService );
356
- if (!hashResult.IsSuccess ())
357
- {
358
- AWS_LOGSTREAM_ERROR (v4LogTag, " Unable to hmac (sha256) request string \" " << AWS4_REQUEST << " \" " );
359
- return " " ;
360
- }
361
-
362
- auto kSigning = hashResult.GetResult ();
363
- hashResult = m_HMAC->Calculate (ByteBuffer ((unsigned char *)stringToSign.c_str (), stringToSign.length ()), kSigning );
328
+ auto & partialSignature = ComputeLongLivedHash (credentials.GetAWSSecretKey (), simpleDate);
329
+
330
+ auto hashResult = m_HMAC->Calculate (ByteBuffer ((unsigned char *)stringToSign.c_str (), stringToSign.length ()), partialSignature);
364
331
if (!hashResult.IsSuccess ())
365
332
{
366
333
AWS_LOGSTREAM_ERROR (v4LogTag, " Unable to hmac (sha256) final string \" " << stringToSign << " \" " );
@@ -378,9 +345,14 @@ Aws::String AWSAuthV4Signer::GenerateSignature(const AWSCredentials& credentials
378
345
379
346
Aws::String AWSAuthV4Signer::ComputePayloadHash (Aws::Http::HttpRequest& request) const
380
347
{
348
+ if (!request.GetContentBody ())
349
+ {
350
+ AWS_LOGSTREAM_DEBUG (v4LogTag, " Using cached empty string sha256 " << EMPTY_STRING_SHA256 << " because payload is empty." );
351
+ return EMPTY_STRING_SHA256;
352
+ }
353
+
381
354
// compute hash on payload if it exists.
382
- auto hashResult = request.GetContentBody () ? m_hash->Calculate (*request.GetContentBody ())
383
- : m_hash->Calculate (" " );
355
+ auto hashResult = m_hash->Calculate (*request.GetContentBody ());
384
356
385
357
if (request.GetContentBody ())
386
358
{
@@ -411,3 +383,64 @@ Aws::String AWSAuthV4Signer::GenerateStringToSign(const Aws::String& dateValue,
411
383
412
384
return ss.str ();
413
385
}
386
+
387
+ const Aws::Utils::Array<unsigned char >& AWSAuthV4Signer::ComputeLongLivedHash (const Aws::String& secretKey, const Aws::String& simpleDate) const
388
+ {
389
+ // only compute this once and use it until either the credentials change, or the date changes.
390
+ if (m_currentDateStr != simpleDate || m_currentSecretKey != secretKey)
391
+ {
392
+ std::lock_guard<std::mutex> locker (m_partialSignatureLock);
393
+ if (m_currentDateStr != simpleDate || m_currentSecretKey != secretKey)
394
+ {
395
+ m_currentSecretKey = secretKey;
396
+ m_currentDateStr = simpleDate;
397
+
398
+ // now we do the complicated part of deriving a signing key.
399
+ Aws::String signingKey (SIGNING_KEY);
400
+
401
+ signingKey.append (m_currentSecretKey);
402
+
403
+ // we use digest only for the derivation process.
404
+ auto hashResult = m_HMAC->Calculate (ByteBuffer ((unsigned char *)simpleDate.c_str (), simpleDate.length ()),
405
+ ByteBuffer ((unsigned char *)signingKey.c_str (), signingKey.length ()));
406
+
407
+ if (!hashResult.IsSuccess ())
408
+ {
409
+ AWS_LOGSTREAM_ERROR (v4LogTag, " Failed to hmac (sha256) date string \" " << simpleDate << " \" " );
410
+ m_partialSignature = ByteBuffer ();
411
+ return m_partialSignature;
412
+ }
413
+
414
+ auto kDate = hashResult.GetResult ();
415
+ hashResult = m_HMAC->Calculate (ByteBuffer ((unsigned char *)m_region.c_str (), m_region.length ()), kDate );
416
+ if (!hashResult.IsSuccess ())
417
+ {
418
+ AWS_LOGSTREAM_ERROR (v4LogTag, " Failed to hmac (sha256) region string \" " << m_region << " \" " );
419
+ m_partialSignature = ByteBuffer ();
420
+ return m_partialSignature;
421
+ }
422
+
423
+ auto kRegion = hashResult.GetResult ();
424
+ hashResult = m_HMAC->Calculate (ByteBuffer ((unsigned char *)m_serviceName.c_str (), m_serviceName.length ()), kRegion );
425
+ if (!hashResult.IsSuccess ())
426
+ {
427
+ AWS_LOGSTREAM_ERROR (v4LogTag, " Failed to hmac (sha256) service string \" " << m_serviceName << " \" " );
428
+ m_partialSignature = ByteBuffer ();
429
+ return m_partialSignature;
430
+ }
431
+
432
+ auto kService = hashResult.GetResult ();
433
+ hashResult = m_HMAC->Calculate (ByteBuffer ((unsigned char *)AWS4_REQUEST, strlen (AWS4_REQUEST)), kService );
434
+ if (!hashResult.IsSuccess ())
435
+ {
436
+ AWS_LOGSTREAM_ERROR (v4LogTag, " Unable to hmac (sha256) request string \" " << AWS4_REQUEST << " \" " );
437
+ m_partialSignature = ByteBuffer ();
438
+ return m_partialSignature;
439
+ }
440
+
441
+ m_partialSignature = hashResult.GetResult ();
442
+ }
443
+ }
444
+
445
+ return m_partialSignature;
446
+ }
0 commit comments