package utils.security; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLEncoder; import java.net.URLDecoder; import java.util.TreeMap; import java.util.Map; import java.util.Iterator; import org.apache.commons.codec.binary.Base64; public class SigHelper { private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1"; public static String getSignedUrl(String url, String key) throws Exception { return url + "&Signature=" + URLEncoder.encode(getSignature(url, key), "UTF-8"); } public static String getSignature(String url, String key) throws Exception { URL u = new URL(url); return computeSignature(key, makeParamMap(u.getQuery())); } private static String computeSignature(String callerSecretKey, TreeMap sortedMap) throws Exception { StringBuffer strToSign = new StringBuffer(""); // Raise exception if caller key unknown if (callerSecretKey == null || callerSecretKey.equals("")) throw new RuntimeException("Invalid callid for computeSignature"); for (Iterator i = sortedMap.entrySet().iterator(); i.hasNext();) { Map.Entry e = (Map.Entry) i.next(); String key = (String) e.getKey(); String[] value = (String[]) e.getValue(); for (int j = 0; j < value.length; j++) { System.out.println("SigHelper.java: From parameter '" + key + "' adding " + " value '" + value[j] + "'"); strToSign.append(key); strToSign.append(value[j]); } } System.out.println("SigHelper.java: Attempting to sign string '" + strToSign.toString()); return calculateSig(callerSecretKey, strToSign.toString()); } private static String calculateSig(String secretKey, String parametersToHash) { String result; try { SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(), HMAC_SHA1_ALGORITHM); Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM); mac.init(signingKey); byte[] rawHmac = mac.doFinal(parametersToHash.getBytes()); String encodedHMac = new String (Base64.encodeBase64Chunked (rawHmac)); // The following API behaves differently on windows and Linux if (System.getProperty("os.name").startsWith("Windows")) result = encodedHMac.substring(0, encodedHMac.length() - 2); else result = encodedHMac.substring(0, encodedHMac.length() - 2); } catch (Exception e) { throw new RuntimeException("Error Calculating Hmac", e); } return result; } private static TreeMap makeParamMap(String queryString) throws UnsupportedEncodingException { TreeMap hmp = new TreeMap(String.CASE_INSENSITIVE_ORDER); String[] param = queryString.split("&"); for (int i = 0; i < param.length; i++) { int index = param[i].indexOf("="); String key = param[i].substring(0, index); String value = param[i].substring(index + 1); System.out.println("SigHelper.java: Adding " + key + " = " + value); if (hmp.get(key) == null) hmp.put(key, new String[] { URLDecoder.decode(value, "UTF-8") }); else { // Very Rare Case String[] arr = (String[]) hmp.get(key); String[] arrNew = new String[arr.length + 1]; arrNew[arr.length] = URLDecoder.decode(value, "UTF-8"); for (int j = 0; j < arr.length; j++) arrNew[j] = arr[j]; } } return hmp; } }