Java – how to create a signature using hmacsha1 and a key to connect to the Kayako API
I'm trying to connect to a third-party application API using Apache commons HTTP client The API I'm trying to connect to is http://wiki.kayako.com/display/DEV/REST +API.
The API requires me to pass the API key and signature, as well as the salt used to create the signature
According to the API documentation, these are the steps to create a signature
>Generate a random string to create salt (in PHP, you will use mt_and() to do this) > generate a signature by using sha256 hash salt, And use the key as the key (in PHP, you will use hash_hmac() to do this) > Base64 encoded signature (in PHP, you will use base64_encode() to do this) > URL encoded output (in PHP, you will use urlencode() to do this)
to update
According to the reply I received, I changed some code and created a mock account with Kayako to test the API
I am using the following classes to generate signatures
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.GeneralSecurityException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.util.encoders.Base64Encoder; public class GenSign2 { public static void main(String[] args) throws GeneralSecurityException,IOException { String secretKey = "M2Y2YjkxZDEtYmNlOC1mYmI0LTkxZTgtOTNiY2RiMDhmN2E2YjExNGUwYjktNGJkYy1jZTM0LWQ1MWYtZGIwYWRlZTE0NGNh"; String salt = "0123456789"; String generateHmacSHA256Signature = generateHmacSHA256Signature(salt,secretKey); System.out.println("Signature: " + generateHmacSHA256Signature); String urlEncodedSign = URLEncoder.encode(generateHmacSHA256Signature,"UTF-8"); System.out.println("Url encoded value: " + urlEncodedSign); } public static String generateHmacSHA256Signature(String data,String key) throws GeneralSecurityException,IOException { byte[] hmacData = null; try { SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"),"HmacSHA256"); Mac mac = Mac.getInstance("HmacSHA256"); mac.init(secretKey); hmacData = mac.doFinal(data.getBytes("UTF-8")); ByteArrayOutputStream bout = new ByteArrayOutputStream(); new Base64Encoder().encode(hmacData,hmacData.length,bout); return bout.toString("UTF-8"); } catch (UnsupportedEncodingException e) { throw new GeneralSecurityException(e); } } }
The test API is as follows
import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; public class TestApi { public static void main(String[] args) throws ClientProtocolException,IOException,URISyntaxException { HttpClient client = new DefaultHttpClient(); List<NameValuePair> qparams = new ArrayList<NameValuePair>(); qparams.add(new BasicNameValuePair("apikey","f165dc40-ce3f-6864-7d5e-27a7188b2e62")); qparams.add(new BasicNameValuePair("salt","0123456789")); qparams.add(new BasicNameValuePair("signature","mbrhpXkP0LzNMNDygHAorqMx%2FDGovl%2FauMTOMB6RNMA%3D")); HttpPost httpget = new HttpPost( "http://aruntest.kayako.com/api/index.PHP?e=/Core/Test"); HttpResponse response = client.execute(httpget); System.out.println(response.getProtocolVersion()); System.out.println(response.getStatusLine().getStatusCode()); System.out.println(response.getStatusLine().getReasonPhrase()); System.out.println(response.getStatusLine().toString()); } }
You can access the demo site using: http://aruntest.kayako.com/admin/ User: admin Password: ty386rhjzz
When I try to connect, it throws an unauthorized access exception
Solution
Try and compare your signature method to this one (it works)
public static String generateHmacSHA256Signature(String data,String key) throws GeneralSecurityException { byte[] hmacData = null; try { SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"),"HmacSHA256"); Mac mac = Mac.getInstance("HmacSHA256"); mac.init(secretKey); hmacData = mac.doFinal(data.getBytes("UTF-8")); return new BASE64Encoder().encode(hmacData); } catch (UnsupportedEncodingException e) { // TODO: handle exception throw new GeneralSecurityException(e); } }
The result of this call will be the value of your property signature
String signature = generateHmacSHA256Signature(salt,key); qparams.add(new BasicNameValuePair("signature",signature));
A simple way to generate salt / nonce
String nonce = String.valueOf(System.currentTimeMillis());
See example: