· 6 years ago · Aug 12, 2019, 05:24 AM
1import org.apache.commons.codec.binary.Hex;
2
3import javax.crypto.Mac;
4import javax.crypto.spec.SecretKeySpec;
5import java.io.UnsupportedEncodingException;
6import java.net.URLEncoder;
7import java.nio.charset.StandardCharsets;
8import java.security.InvalidKeyException;
9import java.security.MessageDigest;
10import java.security.NoSuchAlgorithmException;
11import java.text.SimpleDateFormat;
12import java.util.*;
13
14public class AWSHelper {
15 private String bytesToHex(byte[] bytes) {
16 StringBuffer result = new StringBuffer();
17 for (byte byt : bytes) result.append(Integer.toString((byt & 0xff) + 0x100, 16).substring(1));
18 return result.toString();
19 }
20
21 public byte[] sign(byte[] keyString, String msg) {
22 String algo = "HmacSHA256";
23 byte[] digest = null;
24
25 try {
26 SecretKeySpec key = new SecretKeySpec(keyString, algo);
27 Mac mac = Mac.getInstance(algo);
28 mac.init(key);
29 digest = mac.doFinal(msg.getBytes("UTF-8"));
30 } catch (UnsupportedEncodingException e) {
31 } catch (InvalidKeyException e) {
32 } catch (NoSuchAlgorithmException e) {
33 }
34 return digest;
35 }
36
37 private byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Throwable{
38 byte[] kDate = sign(("AWS4" + key).getBytes("UTF-8"), dateStamp);
39 byte[] kRegion = sign(kDate, regionName);
40 byte[] kService = sign(kRegion, serviceName);
41 byte[] kSigning = sign(kService, "aws4_request");
42 return kSigning;
43 }
44
45 private String urlEncode(String txt){
46 return URLEncoder.encode(txt, StandardCharsets.UTF_8);
47 }
48
49 public String generatePresignedUrlMqtt(String iotHost, String iotRegion, String accessKey, String secretKey) throws Throwable{
50 String method = "GET";
51 String service = "iotdevicegateway";
52 String host = iotHost;
53 String region = iotRegion;
54 String canonicalUri = "/mqtt";
55
56 // Create a date for headers and the credential string
57 SimpleDateFormat timestampFormat = new SimpleDateFormat("YMMdd'T'hhmmss'Z'");
58 SimpleDateFormat dateFormat = new SimpleDateFormat("YMMdd");
59 timestampFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
60
61 String algorithm = "AWS4-HMAC-SHA256";
62
63 String amzdate = timestampFormat.format(new Date());
64 String datestamp = dateFormat.format(new Date());
65
66 String credentialScope = datestamp + '/' + region + '/' + service + '/' + "aws4_request";
67
68 StringBuilder canonicalQuerystring = new StringBuilder(
69 String.format("X-Amz-Algorithm=%s", algorithm)+ "&"
70 );
71 canonicalQuerystring.append(
72 String.format("X-Amz-Credential=%s", urlEncode(String.format("%s/%s", accessKey, credentialScope)))+ "&"
73 );
74 canonicalQuerystring.append(
75 String.format("X-Amz-Date=%s", amzdate) + "&"
76 );
77 canonicalQuerystring.append(
78 String.format("X-Amz-SignedHeaders=host")
79 );
80
81 String canonicalHeaders = "host:" + host + "\n";
82 MessageDigest digest = MessageDigest.getInstance("SHA-256");
83 String payloadHash = this.bytesToHex(digest.digest("".getBytes(StandardCharsets.UTF_8)));
84 String canonicalRequest = method + "\n" + canonicalUri + "\n" + canonicalQuerystring.toString() + '\n' + canonicalHeaders + "\nhost\n" + payloadHash;
85 String stringToSign = algorithm + "\n" + amzdate + "\n" + credentialScope + "\n" + this.bytesToHex(digest.digest(canonicalRequest.getBytes(StandardCharsets.UTF_8)));
86
87 byte[] signingKey = getSignatureKey(secretKey, datestamp, region, service);
88
89 String signature = Hex.encodeHexString(this.sign(signingKey, stringToSign));
90 String signedUrl = "wss://" + host + canonicalUri + "?" + canonicalQuerystring.toString() +"&X-Amz-Signature=" + signature;
91 return signedUrl;
92 }
93}