Created
March 17, 2023 08:29
-
-
Save cm-kazup0n/bd4703b118ae865b030acb7813a316c5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.security.MessageDigest | |
import java.text.SimpleDateFormat | |
import java.util.{Date, TimeZone} | |
object AwsV4Signer { | |
def sign(accessKey: String, secretKey: String, method: String, url: String, payload: String): Map[String, String] = { | |
val timestamp = getFormattedTimestamp() | |
val credentialsScope = getCredentialsScope(timestamp) | |
val canonicalRequest = getCanonicalRequest(method, url, payload, credentialsScope) | |
val hashedCanonicalRequest = hash(canonicalRequest) | |
val stringToSign = getStringToSign(timestamp, credentialsScope, hashedCanonicalRequest) | |
val signingKey = getSigningKey(secretKey, credentialsScope) | |
val signature = hmacSHA256(signingKey, stringToSign) | |
val authorizationHeader = getAuthorizationHeader(accessKey, credentialsScope, signature) | |
Map("Authorization" -> authorizationHeader, "X-Amz-Date" -> timestamp) | |
} | |
private def getFormattedTimestamp(): String = { | |
val dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'") | |
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")) | |
dateFormat.format(new Date()) | |
} | |
private def getCredentialsScope(timestamp: String): String = { | |
val date = timestamp.substring(0, 8) | |
s"$date/us-east-1/s3/aws4_request" | |
} | |
private def getCanonicalRequest(method: String, url: String, payload: String, credentialsScope: String): String = { | |
val canonicalUri = getCanonicalUri(url) | |
val canonicalQueryString = getCanonicalQueryString(url) | |
val canonicalHeaders = getCanonicalHeaders(credentialsScope) | |
val payloadHash = hash(payload) | |
s"$method\n$canonicalUri\n$canonicalQueryString\n$canonicalHeaders\n$credentialsScope\n$payloadHash" | |
} | |
private def getCanonicalUri(url: String): String = { | |
val uri = new java.net.URI(url) | |
uri.getPath() | |
} | |
private def getCanonicalQueryString(url: String): String = { | |
val uri = new java.net.URI(url) | |
val query = uri.getQuery() | |
if (query == null) "" else query | |
} | |
private def getCanonicalHeaders(credentialsScope: String): String = { | |
s"host:s3.amazonaws.com\nx-amz-date:$timestamp\nx-amz-security-token:$securityToken\n" | |
} | |
private def getStringToSign(timestamp: String, credentialsScope: String, hashedCanonicalRequest: String): String = { | |
s"AWS4-HMAC-SHA256\n$timestamp\n$credentialsScope\n$hashedCanonicalRequest" | |
} | |
private def getSigningKey(secretKey: String, credentialsScope: String): Array[Byte] = { | |
val kDate = hmacSHA256(s"AWS4$secretKey", credentialsScope.substring(0, 8).getBytes("UTF-8")) | |
val kRegion = hmacSHA256(kDate, "us-east-1".getBytes("UTF-8")) | |
val kService = hmacSHA256(kRegion, "s3".getBytes("UTF-8")) | |
hmacSHA256(kService, "aws4_request".getBytes("UTF-8")) | |
} | |
private def getAuthorizationHeader(accessKey: String, credentialsScope: String, signature: String): String = { | |
s"AWS4-HMAC-SHA256 Credential=$accessKey/$credentialsScope, SignedHeaders |
Author
cm-kazup0n
commented
Mar 17, 2023
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment