Подписание политики Amazon S3 в Java - PullRequest
7 голосов
/ 06 января 2012

По какой-то причине я борюсь с созданием подписи для моей политики загрузки Amazon S3. Я клянусь, у меня это работало однажды, но больше не. Любая помощь приветствуется. Мне нужен свежий набор глаз.

При сравнении с Amazon S3 Signature Tester я не получаю такую ​​же подпись. Однако, когда я напрямую использую подпись, исходящую от этого инструмента, все работает отлично. Так что проблема определенно в моем процессе подписания. Кроме того, шестнадцатеричное декодирование строки для подписи, полученное из этого инструмента, идентично моей подписанной политике ввода.

Документы AWS говорят , что процесс создания сигнатуры политики должен выглядеть следующим образом:

  1. Кодировать политику с использованием UTF-8.
  2. Кодировать эти байты UTF-8, используя Base64.
  3. Подпишите политику с помощью секретного ключа доступа, используя HMAC SHA-1.
  4. Кодирование подписи SHA-1 с использованием Base64.

Кажется, достаточно просто. Единственное место для двусмысленности может быть в # 3. Документы AWS показывают образец фрагмента для генерации HMAC-SHA1 , и это согласуется с другими примерами криптографии Java , которые я видел.

Я использую v1.6 реализации Apache Commons Base64. Мой код подписи в основном выглядит так:

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

/* ... */

private static final String UTF8 = "UTF-8";
private static final String HMACSHA1 = "HmacSHA1";

public static String sign(String secret, String data) {
    byte[] dataBytes = data.getBytes(UTF8);
    byte[] secretBytes = secret.getBytes(UTF8);

    SecretKeySpec signingKey = new SecretKeySpec(secretBytes, HMACSHA1);

    Mac mac = Mac.getInstance(HMACSHA1);
    mac.init(signingKey);
    byte[] signature = mac.doFinal(dataBytes);

    return Base64.encodeBase64String(signature);
}

И тогда мое использование этой подписи выглядит так:

String signature = sign(
    /* AWS Secret Access Key copied directly out of the AWS Console */,
    /* policy properly serialized as JSON */);

Ответы [ 3 ]

5 голосов
/ 06 января 2012

Хорошо, я нашел это. Очевидно сегодня я эффективно пропустил шаг # 2. Я кодировал политику JSON как Base64, но затем я непосредственно подписываю строку JSON, а не строку Base64.

Шаг № 3, вероятно, следует перефразировать так: «Подписать политику Base64 с помощью секретного ключа доступа с помощью HMAC SHA-1.»

Полагаю, я оставлю это, если кто-нибудь еще столкнется с подобной проблемой.

3 голосов
/ 01 января 2013

Теперь эта процедура официально поддерживается.http://aws.amazon.com/articles/1434

import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

String policy = (new BASE64Encoder()).encode(
policy_document.getBytes("UTF-8")).replaceAll("\n","").replaceAll("\r","");

Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(
aws_secret_key.getBytes("UTF-8"), "HmacSHA1"));
String signature = (new BASE64Encoder()).encode(
hmac.doFinal(policy.getBytes("UTF-8")))
.replaceAll("\n", "");

* Остерегайтесь реализации окна для этого примера, поскольку в комментариях к сообщению также было указано на найденную проблему.

Результат может бытьпроверено этим http://s3.amazonaws.com/doc/s3-example-code/post/post_sample.html

Однако некоторые говорят, что этот "org.apache.commons.codec.binary.Base64" лучше из-за этого.http://www.asgarli.net/2011/03/replacing-sunmiscbase64encoder-and.html

0 голосов
/ 12 июня 2012
String policy_document =
      "{\"expiration\": \"2009-01-01T00:00:00Z\"," +
        "\"conditions\": [" +
          "{\"bucket\": \"s3-bucket\"}," +
          "[\"starts-with\", \"$key\", \"uploads/\"]," +
          "{\"acl\": \"private\"}," +
          "{\"success_action_redirect\": \"http://localhost/\"}," +
          "[\"starts-with\", \"$Content-Type\", \"\"]," +
          "[\"content-length-range\", 0, 1048576]" +
        "]" +
      "}";

    // Calculate policy and signature values from the given policy document and AWS credentials.
    String policy = new String(
        Base64.encodeBase64(policy_document.getBytes("UTF-8")), "ASCII");

    Mac hmac = Mac.getInstance("HmacSHA1");
    hmac.init(new SecretKeySpec(
        aws_secret_key.getBytes("UTF-8"), "HmacSHA1"));
    String signature = new String(
        Base64.encodeBase64(hmac.doFinal(policy.getBytes("UTF-8"))), "ASCII");
...