如何使用HMACSHA1和密钥创建签名以连接到Kayako API

时间:2011-03-12 04:51:15

标签: java encryption

我正在尝试使用apache commons HTTP Client连接到第三方应用程序API。我正在尝试连接的API是http://wiki.kayako.com/display/DEV/REST+API

API要求我传递API密钥和签名以及用于创建签名的salt。

根据API文档,这些是创建签名的步骤

  1. 生成随机字符串以创建salt(在PHP中,您将使用mt_and()来执行此操作)
  2. 使用SHA256使用密钥作为密钥散列盐来生成签名(在PHP中,您将使用hash_hmac()来执行此操作)
  3. base64编码签名(在PHP中,你将使用base64_encode()来执行此操作)
  4. URL对输出进行编码(在PHP中,您将使用urlencode()执行此操作)
  5. 已更新

    根据我得到的回复,我更改了一些代码并使用Kayako创建了一个模拟帐户来测试API

    我正在使用以下类生成签名

    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, 0, hmacData.length, bout);
                return bout.toString("UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new GeneralSecurityException(e);
            }
        }
    }
    

    测试api如下

    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());
        }
    
    }
    

    可以使用访问演示站点 网址:http://aruntest.kayako.com/admin/
    用户:admin
    密码:ty386rhjzz

    当我尝试连接时,它会抛出未经授权的访问异常。

3 个答案:

答案 0 :(得分:4)

尝试并将您的签名方法与此进行比较(可行)

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);
    }
}

此次调用的结果将是您的属性签名

String signature = generateHmacSHA256Signature(salt, key);
qparams.add(new BasicNameValuePair("signature", signature));

生成salt / nonce的简单方法

String nonce = String.valueOf(System.currentTimeMillis());

请参阅Example:

答案 1 :(得分:1)

Kayako已使用新的java sample更新了他们的文档,该工作正常。

答案 2 :(得分:0)

我认为整个getSaltedKey()例程是不必要的。您只是使用HMAC签署盐(它应该被称为nonce)并使用提供的密钥签名,看起来您不应该签署密钥+盐。