Skip to content

Instantly share code, notes, and snippets.

@tuvshuud
Last active July 31, 2019 09:14
Show Gist options
  • Save tuvshuud/d10dd34eee868427b68361df6da9d960 to your computer and use it in GitHub Desktop.
Save tuvshuud/d10dd34eee868427b68361df6da9d960 to your computer and use it in GitHub Desktop.
Java helper class to generate presigned url for AWS IoT MQTT device gateway
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
public class AWSHelper {
private String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte byt : bytes) result.append(Integer.toString((byt & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
public byte[] sign(byte[] keyString, String msg) {
String algo = "HmacSHA256";
byte[] digest = null;
try {
SecretKeySpec key = new SecretKeySpec(keyString, algo);
Mac mac = Mac.getInstance(algo);
mac.init(key);
digest = mac.doFinal(msg.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
} catch (InvalidKeyException e) {
} catch (NoSuchAlgorithmException e) {
}
return digest;
}
private byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Throwable{
byte[] kDate = sign(("AWS4" + key).getBytes("UTF-8"), dateStamp);
byte[] kRegion = sign(kDate, regionName);
byte[] kService = sign(kRegion, serviceName);
byte[] kSigning = sign(kService, "aws4_request");
return kSigning;
}
private String urlEncode(String txt){
return URLEncoder.encode(txt, StandardCharsets.UTF_8);
}
public String generatePresignedUrlMqtt(String iotHost, String iotRegion, String accessKey, String secretKey) throws Throwable{
String method = "GET";
String service = "iotdevicegateway";
String host = iotHost;
String region = iotRegion;
String canonicalUri = "/mqtt";
// Create a date for headers and the credential string
SimpleDateFormat timestampFormat = new SimpleDateFormat("YMMdd'T'hhmmss'Z'");
SimpleDateFormat dateFormat = new SimpleDateFormat("YMMdd");
timestampFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String algorithm = "AWS4-HMAC-SHA256";
String amzdate = timestampFormat.format(new Date());
String datestamp = dateFormat.format(new Date());
String credentialScope = datestamp + '/' + region + '/' + service + '/' + "aws4_request";
StringBuilder canonicalQuerystring = new StringBuilder(
String.format("X-Amz-Algorithm=%s", algorithm)+ "&"
);
canonicalQuerystring.append(
String.format("X-Amz-Credential=%s", urlEncode(String.format("%s/%s", accessKey, credentialScope)))+ "&"
);
canonicalQuerystring.append(
String.format("X-Amz-Date=%s", amzdate) + "&"
);
canonicalQuerystring.append(
String.format("X-Amz-SignedHeaders=host")
);
String canonicalHeaders = "host:" + host + "\n";
MessageDigest digest = MessageDigest.getInstance("SHA-256");
String payloadHash = this.bytesToHex(digest.digest("".getBytes(StandardCharsets.UTF_8)));
String canonicalRequest = method + "\n" + canonicalUri + "\n" + canonicalQuerystring.toString() + '\n' + canonicalHeaders + "\nhost\n" + payloadHash;
String stringToSign = algorithm + "\n" + amzdate + "\n" + credentialScope + "\n" + this.bytesToHex(digest.digest(canonicalRequest.getBytes(StandardCharsets.UTF_8)));
byte[] signingKey = getSignatureKey(secretKey, datestamp, region, service);
String signature = Hex.encodeHexString(this.sign(signingKey, stringToSign));
String signedUrl = "wss://" + host + canonicalUri + "?" + canonicalQuerystring.toString() +"&X-Amz-Signature=" + signature;
return signedUrl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment