Pensé que trataría de obtener la nueva lógica de Solicitud firmada agregada a mi aplicación de lienzo de Facebook, para hacer que esto fuera "fácil" para mí misma. Fui a facebook PHP sdk en GitHub y eché un vistazo al unit tests.¿Cómo puedo obtener los mismos resultados HMAC256 en C# como en las pruebas de unidad PHP?
Mi problema real es que no puedo obtener el hash incluido en la solicitud para que coincida con el hash que calculo usando el secreto de la aplicación, y los datos enviados dentro de la solicitud.
La forma en que esto debe funcionar se describe en Facebook's authentication page.
private string VALID_SIGNED_REQUEST = "ZcZocIFknCpcTLhwsRwwH5nL6oq7OmKWJx41xRTi59E.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOiIxMjczMzU5NjAwIiwib2F1dGhfdG9rZW4iOiIyNTQ3NTIwNzMxNTJ8Mi5JX2VURmtjVEtTelg1bm8zakk0cjFRX18uMzYwMC4xMjczMzU5NjAwLTE2Nzc4NDYzODV8dUk3R3dybUJVZWQ4c2VaWjA1SmJkekdGVXBrLiIsInNlc3Npb25fa2V5IjoiMi5JX2VURmtjVEtTelg1bm8zakk0cjFRX18uMzYwMC4xMjczMzU5NjAwLTE2Nzc4NDYzODUiLCJ1c2VyX2lkIjoiMTY3Nzg0NjM4NSJ9";
private string NON_TOSSED_SIGNED_REQUEST = "laEjO-az9kzgFOUldy1G7EyaP6tMQEsbFIDrB1RUamE.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiJ9";
public void SignedRequestExample()
{
var Encoding = new UTF8Encoding();
string ApplicationSecret = "904270b68a2cc3d54485323652da4d14";
string SignedRequest = VALID_SIGNED_REQUEST;
string ExpectedSignature = SignedRequest.Substring(0, SignedRequest.IndexOf('.'));
string Payload = SignedRequest.Substring(SignedRequest.IndexOf('.') + 1);
// Back & Forth with Signature
byte[] ActualSignature = FromUrlBase64String(ExpectedSignature);
string TestSignature = ToUrlBase64String(ActualSignature);
// Back & Forth With Data
byte[] ActualPayload = FromUrlBase64String(Payload);
string Json = Encoding.GetString(ActualPayload);
string TestPayload = ToUrlBase64String(ActualPayload);
// Attempt to get same hash
var Hmac = SignWithHMAC(ActualPayload, Encoding.GetBytes(ApplicationSecret));
var HmacBase64 = ToUrlBase64String(Hmac);
var HmacHex = BytesToHex(Hmac);
if (HmacBase64 != ExpectedSignature)
{
// YAY
}
else
{
// BOO
}
}
private static string BytesToHex(byte[] input)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in input)
{
sb.Append(string.Format("{0:x2}", b));
}
return sb.ToString();
}
private string ToUrlBase64String(byte[] Input)
{
return Convert.ToBase64String(Input).Replace("=", String.Empty).Replace('+', '-').Replace('/', '_');
}
// http://tools.ietf.org/html/rfc4648#section-5
private byte[] FromUrlBase64String(string Base64UrlSafe)
{
Base64UrlSafe = Base64UrlSafe.PadRight(Base64UrlSafe.Length + (4 - Base64UrlSafe.Length % 4) % 4, '=');
Base64UrlSafe = Base64UrlSafe.Replace('-', '+').Replace('_', '/');
return Convert.FromBase64String(Base64UrlSafe);
}
private byte[] SignWithHMAC(byte[] dataToSign, byte[] keyBody)
{
using (var hmac = new HMACSHA256(keyBody))
{
hmac.ComputeHash(dataToSign);
/*
CryptoStream cs = new CryptoStream(System.IO.Stream.Null, hmac, CryptoStreamMode.Write);
cs.Write(dataToSign, 0, dataToSign.Length);
cs.Flush();
cs.Close();
byte[] hashResult = hmac.Hash;
*/
return hmac.Hash;
}
}
public string Base64ToHex(string input)
{
StringBuilder sb = new StringBuilder();
byte[] inputBytes = Convert.FromBase64String(input);
foreach (byte b in inputBytes)
{
sb.Append(string.Format("{0:x2}", b));
}
return sb.ToString();
}
respuesta gracias a Rasmus a continuación, para ayudar a alguien más aquí es la (código limpiado) actualización:
/// Example signed_request variable from PHPSDK Unit Testing
private string VALID_SIGNED_REQUEST = "ZcZocIFknCpcTLhwsRwwH5nL6oq7OmKWJx41xRTi59E.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOiIxMjczMzU5NjAwIiwib2F1dGhfdG9rZW4iOiIyNTQ3NTIwNzMxNTJ8Mi5JX2VURmtjVEtTelg1bm8zakk0cjFRX18uMzYwMC4xMjczMzU5NjAwLTE2Nzc4NDYzODV8dUk3R3dybUJVZWQ4c2VaWjA1SmJkekdGVXBrLiIsInNlc3Npb25fa2V5IjoiMi5JX2VURmtjVEtTelg1bm8zakk0cjFRX18uMzYwMC4xMjczMzU5NjAwLTE2Nzc4NDYzODUiLCJ1c2VyX2lkIjoiMTY3Nzg0NjM4NSJ9";
public bool ValidateSignedRequest()
{
string applicationSecret = "904270b68a2cc3d54485323652da4d14";
string[] signedRequest = VALID_SIGNED_REQUEST.Split('.');
string expectedSignature = signedRequest[0];
string payload = signedRequest[1];
// Attempt to get same hash
var Hmac = SignWithHmac(UTF8Encoding.UTF8.GetBytes(payload), UTF8Encoding.UTF8.GetBytes(applicationSecret));
var HmacBase64 = ToUrlBase64String(Hmac);
return (HmacBase64 == expectedSignature);
}
private string ToUrlBase64String(byte[] Input)
{
return Convert.ToBase64String(Input).Replace("=", String.Empty)
.Replace('+', '-')
.Replace('/', '_');
}
private byte[] SignWithHmac(byte[] dataToSign, byte[] keyBody)
{
using (var hmacAlgorithm = new HMACSHA256(keyBody))
{
hmacAlgorithm.ComputeHash(dataToSign);
return hmacAlgorithm.Hash;
}
}
Voy a salir a un miembro aquí y decir que eres un C/Codificador de C++ que apenas conoce C#. –
Hola Steven, no tan nuevo, acabo de meterme en un mal lugar hoy. Pensé que las mentes colectivas del desbordamiento de la pila podrían sacarme. – CameraSchoolDropout
¿No quieres decir 'return (HmacBase64 == expectedSignature);'? Esperaría que el método sea verdadero si la firma era correcta. –