Andrew
Andrew

Reputation: 3613

AWS SignatureDoesNotMatch

Receiving:

SignatureDoesNotMatchThe request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.

With the following:

String associateTag = "example-20";
String awsAccessKeyId = "accessKeyId";
String awsSecretKey = "secretKey";
String endpoint = "webservices.amazon.com";
String uri = "/onca/xml";
String charset = "UTF8";

private String buildQueryString(String keywords) {
    Map<String,String> params = new ArrayMap<>();
    List<String> pairs = new ArrayList<>();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));

    params.put("Service","AWSECommerceService");
    params.put("Operation","ItemSearch");
    params.put("AWSAccessKeyId",awsAccessKeyId);
    params.put("AssociateTag",associateTag);
    params.put("SearchIndex","All");
    params.put("ResponseGroup","Images,ItemAttributes");
    params.put("Timestamp",sdf.format(new Date()));
    params.put("Keywords", keywords);

    Map<String, String> treeMap = new TreeMap<>(params);
    try {
        for (Map.Entry<String, String> param : treeMap.entrySet()) {
            pairs.add(URLEncoder.encode(param.getKey(), charset) + "=" + URLEncoder.encode(param.getValue(), charset));
        }
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    String queryString = "";
    for (int i = 0; i < pairs.size(); i++) {
        if (i != 0) {
            queryString += "&";
        }

        queryString += pairs.get(i);
    }

    Log.d(TAG, "queryString: " + queryString);

    return queryString;
}

private String buildSignature(String queryString) {
    String hash = "";

    try {
        String message = "GET\n" + endpoint + "\n" + uri + "\n" + queryString;
        Log.d(TAG, "message: " + message);

        Mac sha_HMAC = Mac.getInstance("HmacSHA256");

        SecretKeySpec secret_key = new SecretKeySpec(awsSecretKey.getBytes(charset), "HmacSHA256");
        sha_HMAC.init(secret_key);

        hash = Base64.encodeToString(sha_HMAC.doFinal(message.getBytes(charset)), Base64.DEFAULT);
    }
    catch (Exception e){
        System.out.println("Error");
    }

    return hash;
}

public void searchProducts(String keywords) {
    String requestUrl = "";
    String queryString = buildQueryString(keywords);
    String signature = buildSignature(queryString);

    Log.d(TAG, "signature: " + signature);

    try {
        requestUrl = "http://" + endpoint + uri + "?" + queryString + "&Signature=" + URLEncoder.encode(signature, charset);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    Log.d(TAG, "requestUrl: " + requestUrl);

        Ion.with(context)
            .load(requestUrl)
            .asString()
            .setCallback(new FutureCallback<String>() {
                @Override
                public void onCompleted(Exception e, String result) {
                    Log.d(TAG, "searchProducts result: " + result);
                }
            });
}

What could be the problem?

Upvotes: 2

Views: 656

Answers (6)

Tcheutchoua Steve
Tcheutchoua Steve

Reputation: 556

Can be caused by

  1. A space in the name (or path) of the file.

  2. Characters that are not being properly encoded. Mostly / or +.

    Generating new keys that does not contain these characters could help. More info on this issue or this one.

Upvotes: 0

Innocent Anigbo
Innocent Anigbo

Reputation: 4797

In the past when I have had this issue, it was to do with system time. Syncing time with NTP fix issue for me

Upvotes: 0

StackKrish
StackKrish

Reputation: 722

Make sure that your system clock is correct. It will be good idea to sync it using NTP. In the past I have seen signature errors when the time is out of sync.

Upvotes: 2

Asneel Singh
Asneel Singh

Reputation: 11

What I've seen before is that this is normally down to permissions . Check access and secret key is correct and you have adequate permissions.

Upvotes: 1

Yangfan
Yangfan

Reputation: 1876

It's hard to tell from the code. A few things to check:

  • Make sure the service you want to reach uses SigV2 signing (or query string signing). New services follow version 4 signing standard.
  • URLEncoder.encode doesn't meet AWS' encoding requirement RFC 3986. You need to apply some fixes to the encoded string.
  • Query strings should be sorted in a case insensitive way.
  • Your credentials are indeed correct.

It's a good idea to see how QueryStringSigner.java is implemented in the official SDK , and Signature Version 2 Signing Process.

PS: what's the reason of not using the offical SDK?

Upvotes: 0

Andrew
Andrew

Reputation: 3613

Changed:

Base64.DEFAULT;

To:

Base64.NO_WRAP;

Upvotes: 0

Related Questions