2012-01-05 27 views
6

Por alguna razón, estoy luchando con la generación de firmas para mi política de carga de Amazon S3. Juro que lo hice funcionar en un punto pero ya no. Cualquier ayuda sería muy apreciada. Necesito un nuevo par de ojos.Política de Amazon S3 Firma en Java

Al comparar con la salida de Amazon S3 Signature Tester, soy no obteniendo la misma firma. Sin embargo, cuando uso directamente la firma que sale de esa herramienta, todo funciona bien. Entonces, definitivamente, el problema está en mi proceso de firma. Además, el descifrado hexadecimal "Cadena a ser firmado" que sale de esa herramienta es idéntico a la firma de mi política de entrada.

Los documentos dicen AWS the process for constructing a policy signature debe ir como esto:

  1. Codificar la política con UTF-8.
  2. Codifique esos bytes UTF-8 utilizando Base64.
  3. Firme la política con su clave de acceso secreta utilizando HMAC SHA-1.
  4. Codifique la firma SHA-1 utilizando Base64.

Parece bastante sencillo. El único lugar para la ambigüedad podría estar en el n. ° 3. Los documentos de AWS muestran a sample snippet for generating HMAC-SHA1 y esto es coherente con other Java cryptography examples que he visto.

Estoy usando v1.6 de Apache Commons implementación de Base64. Mi firma de código, básicamente, es el siguiente:

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

Y entonces mi uso de esta firma se parece a:

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

Respuesta

5

Vale, lo he encontrado. Al parecer hoy he salteado efectivamente el paso # 2. Codifiqué la política JSON como Base64 pero luego estoy directamente firmando la cadena JSON, no la cadena Base64.

El paso # 3 probablemente deba volver a redactarse para "Firmar la política Base64 Base64 con su clave de acceso secreta utilizando HMAC SHA-1."

Supongo que dejaré esto en caso de que alguien más se encuentre con un problema similar.

-1
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"); 
3

Ahora, este procedimiento es oficialmente compatible. 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", ""); 

* Cuidado con la implementación de una ventana para este ejemplo como algunos problema encontrado a partir de los comentarios de la entrada y la solución al problema también fue proporcionado allí.

El resultado puede ser verificado por esta http://s3.amazonaws.com/doc/s3-example-code/post/post_sample.html

Sin embargo, algunos dijeron que este "org.apache.commons.codec.binary.Base64" es mejor debido a esto. http://www.asgarli.net/2011/03/replacing-sunmiscbase64encoder-and.html